Skip to main content

EtherNet/IP Emulator (Python)

ethernetip-emulator is a high level binary communications framework built around cpppo (pronounced ‘c’3*’p’‘o’ in Python) that exposes a set of tags and allows for the programatic execution .

Architecture

.
├───example
│   ├───basic_datatypes
│   │   └─── *.py
│   ├───mfg_line
│   │   └─── *.py
│   ├───orange_pi
│   │   └─── *.py
│   └───raspberry_pi
│       └─── *.py
├───src
│   └───ethernetip_emulator
│       ├───client
│       ├───server
│       │   ├───datatypes
│       │   │   ├───templates
│       │   │   │   └─── *.py
│       │   │   └─── *.py
│       │   └─── *.py
│       └─── *.py
└───tests
    └───server
        ├───datatypes
        │   ├───mock
        │   │   └─── test_*.py
        │   ├───templates
        │   │   └─── test_*.py
        │   └─── test_*.py
        └─── test_*.py
        

Requirements

  • Python 3.10+
  • cpppo (for Ethernet/IP attribute/device behavior)
  • black | Development Dependency (for code formatting)
  • coverage | Developer Dependency (for coverage reporting)
  • RPi.GPIO or OPi.GPIO | Optional Dependency (for gpio i/o)

Getting Started

pip install ethernetip-emulator

A minimal project needs three files:

File Purpose
tags.py Declare tags with @tag_registry.register
actions.py React to tag changes with @actions.<type>.on_change
__main__.py Start the server with device_controller
# __main__.py
from ethernetip_emulator.server.device import AttributeDevice, apidict, device_controller
from ethernetip_emulator.server.tag_specs import tag_registry
import tags    # registers all tags (can also just be imported in __init__.py)
import actions # registers all listeners (can also just be imported in __init__.py)

if __name__ == "__main__":
    server_control = apidict(timeout=1.0)
    AttributeDevice.set_server_control(server_control)

    with AttributeDevice._actions.bind(AttributeDevice):
        device_controller(
            argv=tag_registry.build_argv(base_args=["--print"]),
            attribute_class=AttributeDevice,
            server={"control": server_control},
        )

Guides

Core

Guide Description
Tag Registry Define tags with @tag_registry.register, use namespaced prefixes, and organise tags across files
Actions Read and write tags at runtime, register on_change listeners, and understand key and defer
Device Start and stop the server, understand how tag writes are intercepted, and apply startup defaults

Datatypes

Guide Description
Datatypes Overview All built-in types at a glance, and a step-by-step guide to creating custom datatypes
Basic Datatypes Scalar types: BOOL, integers, floats, and strings — shared get_val / set_val / on_change API
Bool Array BOOLARRAY — bit-level access, list operations, bulk mutations
Numeric Arrays SINTARRAY · USINTARRAY · INTARRAY · UINTARRAY · DINTARRAY · UDINTARRAY · LINTARRAY · ULINTARRAY
Real Arrays REALARRAY · LREALARRAY — same API as numeric arrays with floating-point zero tolerance (1e-9)
String Array SSTRINGARRAY — list operations using "" as the empty slot sentinel

Typical Workflow

┌─────────────────────────────────────────────────────┐
│                    Your Project                     │
│                                                     │
│  tags.py ──────► tag_registry                       │
│                      │                              │
│                       ▼                             │
│  datatypes.py ─► actions.datatype                   │
│                      │                              │
│                       ▼                             │
│  __main__.py ──► device_controller                  │
│                      │                              │
│                       ▼                             │
│              AttributeDevice                        │
│           (intercepts PLC writes)                   │
│                      │                              │
│                       ▼                             │
│  actions.py ──► on_change listeners                 │
│                      │                              │
│                       ▼                             │
│              actions.<type>.set_val / get_val       │
└─────────────────────────────────────────────────────┘
  1. Tags are declared once at import time via @tag_registry.register.
  2. Custom Datatypes can be declared once at import time via @actions.datatype. Although this is completely optional if you like the built-in datatypes
  3. device_controller builds the tag list and starts the EtherNet/IP server.
  4. AttributeDevice intercepts every PLC write and fires the matching on_change listeners.
  5. Listeners use actions.<type> helpers to read state, write back to tags, or trigger application logic.

Project Layout Convention

your_project/
├── __main__.py          # server entrypoint
├── tags.py              # tag definitions
├── actions.py           # on_change handlers
└── datatypes/           # optional: custom datatype classes
    ├── __init__.py
    └── mytype.py

For larger projects, split tags and actions into sub-modules and import them from a top-level __init__.py so all registrations are triggered before the server starts.

Supporting the Development of EtherNet/IP Emulator

EtherNet/IP Emulator's development depends on your contributions. Right now it is just me working on this, so any contributions are welcome!

License

Copyright 2026 Merck KGaA, Darmstadt, Germany and/or its affiliates. All rights reserved.

Metadata

Release files for ethernetip-emulator 0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ethernetip-emulator 0.1
File Size Uploaded
ethernetip_emulator-0.1.tar.gz 22.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ethernetip-emulator 0.1
File Interpreter ABI Platform
ethernetip_emulator-0.1-py3-none-any.whl Python 3 none any Details

Total release size: 67.5 kB

Release files / ethernetip_emulator-0.1.tar.gz

Download URL ethernetip_emulator-0.1.tar.gz
Size 22.3 kB
Tags Source
SHA-256 checksum
How to use checksums
af928cea0a71807a38c8460c0efa14a85145b5e94c7493903b4e1b2dbcd8c7a4
BLAKE2b-256 checksum
How to use checksums
4517293208e00546e925946708f9a2a75818af8eaff7ddf20b21eccb6a5f5841
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Release files / ethernetip_emulator-0.1-py3-none-any.whl

Download URL ethernetip_emulator-0.1-py3-none-any.whl
Size 45.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
942ab56efd207feaa755e208efdbc7292c080e3ceb57a1f1158a589ae9ec3061
BLAKE2b-256 checksum
How to use checksums
54fd244d4e55e2b34787582fda5f9c0c1656f654c6299d85b430c3b2e499c463
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Release history Release notifications | RSS feed

0.2

2 release files

0.1.1

2 release files

This release

0.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page