Read-only EtherNet/IP implicit connection bridge that captures PLC I/O data and publishes it to NATS
Project description
eip2nats - EtherNet/IP to NATS Bridge
Read-only bridge that opens an EtherNet/IP implicit (I/O) connection to a PLC, captures the T2O (Target-to-Originator) data stream and publishes every packet to a NATS subject. It does not write data to the PLC — it acts as a passive listener, similar to a sniffer.
All dependencies (libnats, libEIPScanner) are bundled in the wheel.
Features
- Read-only: Captures PLC I/O data via implicit connection, no writes
- Self-contained: Includes compiled libnats and libEIPScanner
- Zero dependencies: No system library installation required
- Device presets: Built-in assembly constants for known devices (RM75E, etc.)
- High performance: Native C++ bindings with pybind11
- Auto-reconnect: Recovers automatically from connection loss
- Thread-safe: Safe handling of multiple connections
Installation
pip install eip2nats
Pre-built wheels are available on PyPI for Linux and Windows.
Building from Source
If a pre-built wheel is not available for your platform, you can build from source:
Linux:
./setup_project_linux.sh
Windows (PowerShell, requires Visual Studio Build Tools):
.\setup_project_windows.ps1
This automatically:
- Creates a virtual environment in
venv/ - Installs Hatch and pybind11
- Compiles nats.c, EIPScanner and the Python binding
- Creates the wheel
- Installs the wheel in the venv
Usage
# Activate virtual environment
source venv/bin/activate # Linux
.\venv\Scripts\Activate # Windows PowerShell
# Run example
python examples/example_python.py
# Deactivate when done
deactivate
Basic Usage
import eip2nats
# Create bridge (using RM75E device presets)
bridge = eip2nats.EIPtoNATSBridge(
"192.168.17.200", # PLC IP address
"nats://192.168.17.138:4222", # NATS server
"plc.data", # NATS subject/topic
config_assembly=eip2nats.devices.RM75E.CONFIG_ASSEMBLY,
o2t_assembly=eip2nats.devices.RM75E.O2T_ASSEMBLY,
t2o_assembly=eip2nats.devices.RM75E.T2O_ASSEMBLY,
t2o_size=100,
)
# Start
if bridge.start():
import time
print("Bridge running!")
# Monitor
while bridge.is_running():
time.sleep(5)
print(f"RX={bridge.get_received_count()}, "
f"TX={bridge.get_published_count()}")
# Stop
bridge.stop()
More examples in examples/
Requirements
Linux:
- Python 3.7+
- git, cmake, make, g++, python3-venv
Windows:
- Python 3.7+
- git, cmake
- Visual Studio Build Tools (cl.exe)
Development
See DEVELOPMENT.md for the full development guide (VSCode setup, debugging, workflows).
Create Release
hatch build
Manual Build (without setup script)
git clone https://github.com/kliskatek/eip2nats.git
cd eip2nats
pip install hatch pybind11
# Build dependencies
python scripts/build_nats.py
python scripts/build_eipscanner.py
python scripts/build_binding.py
# Create wheel
hatch build
Project Structure
eip2nats/
├── pyproject.toml # Hatch configuration
├── hatch_build.py # Hook for platform-specific wheel
├── README.md
├── DEVELOPMENT.md # VSCode development guide
├── LICENSE # MIT
├── THIRD_PARTY_LICENSES # nats.c and EIPScanner licenses
├── setup_project_linux.sh # Automatic setup (Linux)
├── setup_project_windows.ps1 # Automatic setup (Windows)
├── src/
│ └── eip2nats/
│ ├── __init__.py # Python package
│ ├── bindings.cpp # pybind11 bindings
│ ├── EIPtoNATSBridge.h # C++ header
│ ├── EIPtoNATSBridge.cpp # C++ implementation
│ └── lib/ # Compiled libraries (auto-generated)
│ ├── libnats.so / nats.dll
│ └── libEIPScanner.so / EIPScanner.dll
├── scripts/
│ ├── build_config.py # Shared build configuration
│ ├── build_nats.py # Builds nats.c
│ ├── build_eipscanner.py # Builds EIPScanner
│ ├── build_binding.py # Builds Python binding (.pyd/.so)
│ ├── build_example_cpp.py # Builds C++ example
│ └── binding_CMakeLists.txt # CMake template for binding (Windows)
├── examples/
│ ├── example_python.py # Python example
│ └── example_cpp.cpp # C++ example (debugging)
├── tests/
│ └── test_python.py # Python unit tests
└── build/ # Auto-generated, in .gitignore
├── dependencies/ # nats.c and EIPScanner clones
└── example_cpp/ # Compiled C++ executable
How It Works
-
Build scripts (
scripts/):build_nats.py: Clones and compiles nats.c ->libnats.so/nats.dllbuild_eipscanner.py: Clones and compiles EIPScanner ->libEIPScanner.so/EIPScanner.dllbuild_binding.py: Compiles the Python binding ->.so(Linux) /.pyd(Windows)- All copy binaries to
src/eip2nats/lib/
-
hatch build:- Packages the full
src/eip2nats/(code + binaries) hatch_build.pyforces platform-specific wheel tags- Linux: relative RPATH (
$ORIGIN), Windows:os.add_dll_directory() - The wheel contains everything needed
- Packages the full
-
pip install:- Installs the wheel
- Binaries end up in site-packages
- Python loads libraries automatically
- Works without system dependencies!
Advantages
vs System Libraries:
- No
sudo apt-get installrequired - No version conflicts
- Portable across systems
vs Regular Wheels:
- Includes all C/C++ dependencies
- Single file to install
- Works on systems without compilers
vs Docker:
- Lighter (MBs vs GBs)
- Direct Python integration
- No Docker privileges required
API Reference
Class: EIPtoNATSBridge
bridge = eip2nats.EIPtoNATSBridge(
plc_address: str,
nats_url: str,
nats_subject: str,
use_binary_format: bool = True,
config_assembly: int = 4, # Configuration assembly instance
o2t_assembly: int = 2, # O2T data assembly instance
t2o_assembly: int = 1, # T2O data assembly instance
t2o_size: int = 0, # T2O connection size in bytes
)
Methods:
start() -> bool: Starts the bridgestop() -> None: Stops the bridgeis_running() -> bool: Bridge statusget_received_count() -> int: Messages from PLCget_published_count() -> int: Messages to NATSget_reconnect_count() -> int: Automatic EIP reconnections
Device Presets: eip2nats.devices
Pre-defined assembly constants for known EIP devices:
eip2nats.devices.RM75E.CONFIG_ASSEMBLY # 4
eip2nats.devices.RM75E.O2T_ASSEMBLY # 2
eip2nats.devices.RM75E.T2O_ASSEMBLY # 1
Troubleshooting
Error: "cannot open shared object file"
Even though the wheel includes the libraries, check RPATH:
ldd $(python -c "import eip2nats; print(eip2nats.__file__.replace('__init__.py', 'lib/eip2nats.*.so'))")
All dependencies should resolve locally.
Rebuild on Another System
git clone <repo>
cd eip2nats
python scripts/build_nats.py
python scripts/build_eipscanner.py
python scripts/build_binding.py
hatch build
Clean Builds
rm -rf build/ dist/ src/eip2nats/lib/
Changelog
v1.0.0 (2025)
- Initial release
- Self-contained wheel with nats.c and EIPScanner
- Windows (MSVC) and Linux (GCC) support
- Binary and JSON format support
- Thread-safe operations
Contributing
- Fork the project
- Create a branch (
git checkout -b feature/amazing) - Commit changes (
git commit -m 'Add amazing feature') - Push (
git push origin feature/amazing) - Open a Pull Request
License
MIT License - see LICENSE file
Credits
- nats.c - NATS C Client
- EIPScanner - EtherNet/IP Library
- pybind11 - Python bindings
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
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 eip2nats-1.1.0-cp313-cp313-win_amd64.whl.
File metadata
- Download URL: eip2nats-1.1.0-cp313-cp313-win_amd64.whl
- Upload date:
- Size: 412.5 kB
- Tags: CPython 3.13, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8d82a10b2a413368cc89e45c78e531cd22152d94d9e1468d0c651cd46671fcfc
|
|
| MD5 |
3dee45367a60497d42106db95aa0cd13
|
|
| BLAKE2b-256 |
b2866a8f892f0095ed43bdf50fb0a04a6e4d770e92c8e49908dea7b62d23491d
|
File details
Details for the file eip2nats-1.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.
File metadata
- Download URL: eip2nats-1.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
- Upload date:
- Size: 1.6 MB
- Tags: CPython 3.13, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
81a051baa11fce637337437ef2f3a3f476ead15c4254c7ac66a118eef2df004a
|
|
| MD5 |
94ef6c169b2cc1d11137d872886c22e7
|
|
| BLAKE2b-256 |
886f7957a975e3ecdbd76bec3648e1c8f7162c2a478f5228c6158e9f9d2f8870
|
File details
Details for the file eip2nats-1.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl.
File metadata
- Download URL: eip2nats-1.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl
- Upload date:
- Size: 1.5 MB
- Tags: CPython 3.13, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f66b7b145e568c7d73fed7f86545299854ba4685b38a01e751637899e3ca94d0
|
|
| MD5 |
e8e38dcafe6f43447ca9184535bee300
|
|
| BLAKE2b-256 |
ca9b4ef5e6862182434d79be088f5b63870b98275bafd1487a2c0d0d86f07bc5
|
File details
Details for the file eip2nats-1.1.0-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: eip2nats-1.1.0-cp312-cp312-win_amd64.whl
- Upload date:
- Size: 412.5 kB
- Tags: CPython 3.12, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2944abb0fa2c5d7d48ed9a5412a107f860a7a5361df145c82a0602e7d236b1df
|
|
| MD5 |
c7f4f21fba97e5913a1b9375573d628b
|
|
| BLAKE2b-256 |
fffbc9f012e88503a2963db22b0c48925eb4c56e160507b1463d5319e6b9382f
|
File details
Details for the file eip2nats-1.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.
File metadata
- Download URL: eip2nats-1.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
- Upload date:
- Size: 1.6 MB
- Tags: CPython 3.12, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
91c27923d3fe05267ca2d8b5b03e303b19b7f9585683c49341f0b10c114b9a22
|
|
| MD5 |
2990690bb5b90016908987c77d35bf74
|
|
| BLAKE2b-256 |
947ba542cbe1d81fcfdc921ab8311d5d9213e065ebcd6fa48b73494aecef07c5
|
File details
Details for the file eip2nats-1.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl.
File metadata
- Download URL: eip2nats-1.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl
- Upload date:
- Size: 1.5 MB
- Tags: CPython 3.12, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7a9d39776ae5ca6f077eeabf58bea7ef65595cb1864031b70aa065f463901845
|
|
| MD5 |
17abd0b0fc62a533d2f181d3219aaaa8
|
|
| BLAKE2b-256 |
1a75ec9cc12d3a93eda9ee07b25b2e99a7d84705244919dd601c345846f34466
|
File details
Details for the file eip2nats-1.1.0-cp311-cp311-win_amd64.whl.
File metadata
- Download URL: eip2nats-1.1.0-cp311-cp311-win_amd64.whl
- Upload date:
- Size: 411.8 kB
- Tags: CPython 3.11, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ca6e30a2502d646b7147764c851ca9459d66ac0aa5c63b99196bc933eb1bb153
|
|
| MD5 |
d072febdfeaeff2b840bc7812dd532cf
|
|
| BLAKE2b-256 |
9372626000a825382fa0f5b75c636545f9952c9fb70833e5bc54012202c91915
|
File details
Details for the file eip2nats-1.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.
File metadata
- Download URL: eip2nats-1.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
- Upload date:
- Size: 1.6 MB
- Tags: CPython 3.11, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
71585306cd9782dfbc10c20929fe5e6197c10d250e5bb80d5509b07511c9b2e9
|
|
| MD5 |
613eddf72431342f0bde0725dc16a9da
|
|
| BLAKE2b-256 |
6951109259316f7c0e2bc92de0a0b74d721bf2a7f387f7f40402ad8a72a6dff5
|
File details
Details for the file eip2nats-1.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl.
File metadata
- Download URL: eip2nats-1.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl
- Upload date:
- Size: 1.5 MB
- Tags: CPython 3.11, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
795249125fe670b69540253f38ed29af9a395741253ec7f0208c892001651e53
|
|
| MD5 |
67256e8d4968dca779f00b611833a9f2
|
|
| BLAKE2b-256 |
95995631451415a3da429929f79d773a734bbc35ae6b1c298b38ef7c564f32f7
|
File details
Details for the file eip2nats-1.1.0-cp310-cp310-win_amd64.whl.
File metadata
- Download URL: eip2nats-1.1.0-cp310-cp310-win_amd64.whl
- Upload date:
- Size: 410.8 kB
- Tags: CPython 3.10, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6bf9841523ecced2396a8d46dabfe0816e29151c93c42c1b12cc574ffcca8fa5
|
|
| MD5 |
3e14ad54fc177fd305d7bca147de7edc
|
|
| BLAKE2b-256 |
e69bf986d9742d5c6cd6f5297ce459ac38a6c759d6d9c0fe54aec2e7d370c8ef
|
File details
Details for the file eip2nats-1.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.
File metadata
- Download URL: eip2nats-1.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
- Upload date:
- Size: 1.6 MB
- Tags: CPython 3.10, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aa4d8aa8d32985f0f65490c38a7a6143694434dcb2e6763d460f24a74cdc5bd6
|
|
| MD5 |
4b34d85c80965e9fe2679726d1cd6fc1
|
|
| BLAKE2b-256 |
80126674908c84ed4651262f80f03933b730f02fe1a629b3565dad0cfa7ff28b
|
File details
Details for the file eip2nats-1.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl.
File metadata
- Download URL: eip2nats-1.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl
- Upload date:
- Size: 1.5 MB
- Tags: CPython 3.10, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b9c2ddb382631694db04052e3f4f88fddf4006ffd1e248e7f171be40d13c980b
|
|
| MD5 |
42cb3c7de724ea73404c867af61caaa1
|
|
| BLAKE2b-256 |
1a204f991c66d49c5b8dcfb656bf9f997bfbc5eab5b1b88bbf374c7363c7127b
|
File details
Details for the file eip2nats-1.1.0-cp39-cp39-win_amd64.whl.
File metadata
- Download URL: eip2nats-1.1.0-cp39-cp39-win_amd64.whl
- Upload date:
- Size: 409.6 kB
- Tags: CPython 3.9, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
23cd6ec07b607dfed0858405528caa6a84ec3f23d7c2ea9c2bed1781b425a913
|
|
| MD5 |
993e136b6963e4a371602c63c27dd963
|
|
| BLAKE2b-256 |
c1e1a5a1ab5c2525c08b5a2e79e93e374f69778f1fd40e2ce2a8f2f612f4a1b0
|
File details
Details for the file eip2nats-1.1.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.
File metadata
- Download URL: eip2nats-1.1.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
- Upload date:
- Size: 1.6 MB
- Tags: CPython 3.9, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f23f38085ee7dec3d0778907946942a87e20e0179f4a23565b42432ecfc8db2a
|
|
| MD5 |
4700861a9e1d3dd8834161a6cd5d9108
|
|
| BLAKE2b-256 |
05497527dd8f15a3e27ae9adc2909736e82e18776ad962d35a1f968a8a45bcf4
|
File details
Details for the file eip2nats-1.1.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl.
File metadata
- Download URL: eip2nats-1.1.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl
- Upload date:
- Size: 1.5 MB
- Tags: CPython 3.9, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b50cdf7dc446b03cb7b4f86cc6d43ce1727334266f509d50fab4a9797ae82e14
|
|
| MD5 |
22ff16420fd8648d9f211a28296a829d
|
|
| BLAKE2b-256 |
a5a169a71f336110a7198489dd379633a640a85a1b329630b8f057615a4cf544
|