Skip to content
Stevie Chryn edited this page Jul 31, 2026 · 4 revisions

EtherNet/IP Emulator - Wiki

Welcome to the ethernetip-emulator wiki! Ethernetip-emulator is a Python-based EtherNet/IP device emulator built on top of cpppo. It lets you define PLC tags in plain Python, react to tag writes with event-driven callbacks, and run a fully functional EtherNet/IP server — all without physical hardware.

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

How It All Fits Together

┌─────────────────────────────────────────────────────┐
│                    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.

License

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

Clone this wiki locally