EtherNet/IP Scanner Stack

PRE‑CONFORMANCE Scanner // PYTHON BINARIES

System Overview

EtherNet/IP adapts CIP over standard Ethernet to let PLCs and field devices exchange real‑time I/O and configuration data using implicit and explicit messaging.

This scanner implementation turns a Python‑hosted application into a full EtherNet/IP I/O device, exposing CIP objects over UDP for Class 1 I/O and TCP for Class 3 explicit messaging. The library runs as a compiled binary module that you call from Python, so application code remains focused on behavior rather than protocol framing.

The current release targets Linux and Windows environments, with LLDP object behavior available on Linux hosts only.

Technical Capabilities

Object Set
Identity (0x01), Connection Manager (0x06), TCP/IP (0xF5), Ethernet Link (0xF6), Port (0xF4), QoS (0x48), and LLDP Management/Agent (0x109 / 0x10A, Linux‑only).
Messaging Modes
Class 1 implicit I/O and Class 3 explicit messaging, both connected and unconnected, cyclic and change of state, supporting regular and large Forward Open.
Run/Idle Header
O→T and T→O support for the 32‑bit run/idle header, including the additional 4‑byte run/idle segment in the I/O payload.
Unicast & Multicast
T→O producer connections support both unicast and multicast data distribution to consuming adapters.
Timing & Robustness
Validated at RPIs down to 3 ms, 120‑second encapsulation timeout behavior, and 10‑second UCMM flooding tests for stability.
Multi‑Adapter Support
Multiple logical adapters can be added in a single process by assigning separate IPs & Assembly instance ranges (for example A: 100/101/102 and B: 110/111/112).
Python‑First Delivery
Distributed as compiled Python extension modules, consumed from Python via callbacks for I/O, configuration, TCP/IP, Ethernet, LLDP, QoS, and reset handling.
Conformance Status
Designed to align with ODVA recommendations but not yet CT‑certified; suited for early adopters, labs, and production where formal ODVA certification is not a hard requirement.

Python Integration

Imports & Setup
Import EnIP Scanner and setup global state variables.
import Scanner
import os
import time
from random import randint as R
Callback Functions
Log display, I/O data handling, configuration callbacks, and random data generator.
Running = False
Output_Data = {}

def Log():
    global Running
    if not Running:
        Running = True
        os.system('cls')
        for Key, Value in Output_Data.items():
            print(f"{Key}: {Value}")
        time.sleep(0.02)
        Running = False

def IO(Data):
    global Output_Data
    for Key, Value in Data.items():
        Run, IO = Value
        Output_Data[Key] = [Run, IO]
    Log()

def Config(Data):
    for Key, Value in Data.items():
            print(Key, Value)
    
def Random_List(Length, Start, Stop):
    return [R(Start, Stop) for Index in range(Length)]
Scanner Configuration
Configure IP address, register callbacks, and define two assembly instances.
Scanner.Config(IP='192.168.7.7')
Scanner.Register('IO', IO)
Scanner.Register('Config', Config)
Scanner.Register('TCPIP', Config)
Scanner.Register('Ethernet', Config)
Scanner.Register('Reset', Config)
Scanner.Register('LED', Config)
Scanner.Register('LLDP', Config)
Scanner.Register('QoS', Config)

Scanner.Add(Name='A', IP='192.168.7.11', Datatype='UDINT', T_O_Length=4, O_T_Length=8, 
            Config_Length=6, T_O_Instance=100, O_T_Instance=101, Config_Instance=102, 
            T_O_RPI=100000, O_T_RPI=100000, Inhibit=False, T_O_Header=True, O_T_Header=True, 
            Run=True, Unicast=False, Implicit=True, Connected_Explicit=True, Connected_Explicit_Time=1000)
            
Scanner.Add(Name='B', IP='192.168.7.11', Datatype='USINT', T_O_Length=64, O_T_Length=64, 
            Config_Length=32, T_O_Instance=150, O_T_Instance=151, Config_Instance=152, 
            T_O_RPI=200000, O_T_RPI=200000, Inhibit=False, T_O_Header=False, O_T_Header=False, Run=True)
Start & Runtime Loop
Start Scanner service and continuously publish random data.
Scanner.Start()

while True:
    time.sleep(0.01)
    Scanner.Write('A', Random_List(8, 31, 40))
    Scanner.Write('B', Random_List(64, 41, 50))

Resources

The scanner is currently in a pre‑conformance phase: the implementation targets ODVA specifications but has not yet been through official CT testing. The package is provided free of charge as compiled binaries for Python.

User Manual

Object model, scanner lifecycle, and Python API reference.

View

Support

Use the contact page to request features or report interoperability findings.

Contact