TwinEdge /
Resources / EtherNet/IP Integration
EtherNet/IP
Protocol Reference

EtherNet/IP PLC Integration

What TwinEdge expects from a connected Allen-Bradley PLC, how assets and tags are identified, and how raw CIP values are processed into dashboard readings.

Protocol: EtherNet/IP / CIP
Hardware: Allen-Bradley / Rockwell
Port: 44818 TCP

Connection Requirements

ParameterValue
ProtocolEtherNet/IP — CIP explicit messaging over TCP
Port44818
TransportTCP
Connection modelStateless — a new TCP session is opened per read batch and closed after
Timeout5 seconds (configurable per asset)

TwinEdge connects directly to the PLC's EtherNet/IP port using CIP explicit messaging. No EDS file, no ControlLogix backplane slot routing, and no I/O adapter is required — only the controller's IP address and port 44818.

Compatible hardware: CompactLogix (1769-L series), ControlLogix (1756), MicroLogix 1100/1400 with EtherNet/IP adapter, Micro850. Any Rockwell controller that supports CIP explicit messaging will work.


How the System Identifies an Asset

An asset in TwinEdge corresponds to a physical machine or piece of equipment (e.g., a pump, blower, or compressor). Each asset is registered with:

Note: The asset_id is set once at provisioning time. It does not come from the PLC — it is assigned in TwinEdge and used to label all data, OPC UA nodes, and dashboard readings.


Tag Identification

Each sensor mapped to an asset has a corresponding CIP tag on the PLC. The system reads tags by name using CIP explicit messaging.

Tag Name Format

The tag name in TwinEdge must match exactly what is in the PLC (case-sensitive on some firmware versions).

Pump_VibrationX                 → controller-scope scalar tag (name only)
Pump_Status[0]                  → element 0 of an array tag (DINT[])
Program:MainProgram.PumpSpeed   → program-scope tag (full path required)

The system does not use I/O addressing (e.g., Local:0:I.Data) or ladder logic alias tags. Only symbolic controller tags are read.

Controller-Scope vs Program-Scope Tags

In Studio 5000 / RSLogix 5000, every tag lives in one of two places:

Controller-scope tags are defined at the top level of the controller and visible to all programs. These are the standard choice for anything meant to be read externally — HMIs, SCADA, historians, and TwinEdge.

Controller
└── Controller Tags
      ├── Pump_VibrationX      ← read with just the tag name
      ├── Pump_Temperature
      └── Pump_Status

Program-scope tags are defined inside a specific program and local to that program's logic — equivalent to a local variable inside a function. Reading them externally requires the full prefixed path.

Controller
└── Tasks
      └── MainTask
            └── MainProgram
                  └── Program Tags
                        ├── PumpSpeed        ← internal logic variable
                        └── LocalSetpoint

Tag Discovery (Live Browse)

When provisioning a new asset via the dashboard, the system queries the PLC's Symbol Object (CIP class 0x6B). This is Rockwell's standard controller tag table, returning both controller-scope and program-scope tags with their data types.

GroupPath prefixDescription
Controller TagsControllerGlobal tags, accessible from all programs
Program TagsProgram:<name>Scoped to a specific program (e.g., Program:MainProgram)

Practical rule: When receiving a tag list from the PLC programmer, ask whether each tag is a Controller Tag or a Program Tag in Studio 5000. If it is under a Program folder, use the full path. If it is under Controller Tags, use the name as-is.

Configuring Program-Scope Tags

If a tag you need is program-scoped, write the full Program:<name>.<TagName> path in the sensor definition:

# Controller-scope tag — name only
- name: vibration_x
  tag: Pump_VibrationX
  type: REAL
  unit: mm/s

# Program-scope tag — full path required
- name: pump_speed
  tag: "Program:MainProgram.PumpSpeed"
  type: REAL
  unit: rpm

Warning: Without the prefix, the CIP read will look for a controller-scope tag of that name, not find it, and return no value. The sensor will show as missing in the dashboard.


Sensor-to-Tag Mapping

Each sensor entry links an internal sensor name (used by the dashboard, ML, and alerts) to a PLC tag name (what gets sent over CIP).

Mapping Structure

sensors:
  - name: vibration_x          # Internal name — used in dashboard and ML
    tag: Pump_VibrationX       # CIP tag name on the PLC
    type: REAL                 # CIP data type (see table below)
    unit: mm/s                 # Engineering unit label (display only)
    scale_factor: 1.0          # Multiplier applied after reading
    offset_value: 0.0          # Added after scaling
    sample_rate_hz: 10         # How often to poll this tag (per second)

If no tag is specified, the system falls back to using the name field as the tag name.

Array Element Access

For integer status words or any tag backed by a PLC array, specify the element index:

  - name: status_word
    tag: Pump_Status           # Array tag name (no brackets here)
    type: DINT
    element: 0                 # Reads Pump_Status[0]

The system appends [element] to the tag name before sending the CIP read request.


Supported CIP Data Types

The PLC tag's data type must be declared in the asset configuration so the system converts the raw bytes correctly.

CIP TypePLC DescriptionHow It Is Processed
REAL32-bit IEEE 754 floatRead as-is, converted to float
LREAL64-bit IEEE 754 doubleRead as-is, converted to float
DINT32-bit signed integerCast to int, then to float
INT16-bit signed integerCast to int, then to float
SINT8-bit signed integerCast to int, then to float
BOOLBoolean (1 bit)true1.0, false0.0

All values are normalized to float internally. If the PLC returns a list or array wrapper around the value, the system automatically unwraps the first element.

STRING tags are not supported in the data pipeline. Status/mode indicators should use BOOL or DINT instead.


Value Processing Pipeline

Once a raw value is received from the PLC, it passes through these steps before appearing in the dashboard or being evaluated for alerts:

1
PLC Tag Read
Raw CIP bytes received from the controller over TCP port 44818
2
Type Conversion
e.g., DINT raw bytes → Python int → float
3
Scale & Offset
(value × scale_factor) + offset_value
4
Sensor Name Mapping
CIP tag name → internal sensor name (e.g., Pump_VibrationX → vibration_x)
5
OPC UA Node Update
Value written to the asset's OPC UA node in the namespace
S
Storage Service — written to SQLite time-series history
M
ML Inference — anomaly detection / RUL prediction
A
Alert Service — evaluated against configured thresholds

Scale Factor and Offset

Use scale_factor and offset_value when the PLC stores a raw count rather than an engineering value:

engineering_value = (raw_plc_value × scale_factor) + offset_value

Example: PLC stores pressure as raw ADC counts (0–4095 = 0–10 bar):

scale_factor: 0.00244   # 10 / 4095
offset_value: 0.0

If the PLC already stores values in engineering units — as most modern Allen-Bradley programs do — leave both at defaults: scale_factor: 1.0, offset_value: 0.0.


Calculated Values

Sensors derived from multiple tags are defined as calculated_values. These are computed after all raw tags have been read and scaled.

calculated_values:
  - name: pressure_differential
    formula: "pressure_outlet - pressure_inlet"
    unit: bar

  - name: vibration_magnitude
    formula: "sqrt(vibration_x^2 + vibration_y^2 + vibration_z^2)"
    unit: mm/s

Calculated values use internal sensor names (not PLC tag names) in their formulas.


Polling and Timing

SettingDefault
Poll interval1000 ms (1 Hz)
Connection timeout5000 ms
Error retry delay5000 ms

Individual sensors can override the default poll rate via sample_rate_hz. All sensors in an asset are read together in a single CIP batch per poll cycle — set the poll interval to match the fastest sensor's required sample rate.


OPC UA Namespace Layout

After reading from the PLC, sensor values are written into the OPC UA server namespace so that downstream services can subscribe to them:

Root
 └── Assets
     └── {asset_id}  (e.g., Pump_ENIP_001)
          ├── vibration_x  REAL  [mm/s]
          ├── vibration_y  REAL  [mm/s]
          ├── vibration_z  REAL  [mm/s]
          ├── temperature  REAL  [°C]
          ├── pressure_inlet  REAL  [bar]
          ├── pressure_outlet  REAL  [bar]
          ├── flow_rate  REAL  [m³/h]
          ├── motor_current  REAL  [A]
          └── status_word  DINT  (array element 0)

Node names in the OPC UA tree are the internal sensor names, not the PLC tag names.


Alert Thresholds

Alerts reference internal sensor names and calculated values:

alerts:
  - name: high_vibration
    trigger: "vibration_magnitude > 8.0"    # Uses calculated value
    severity: critical

  - name: high_temperature
    trigger: "temperature > 95"             # Uses internal sensor name
    severity: critical

The alert engine never interacts with the PLC directly — it evaluates the already-processed and scaled values from the sensor pipeline.


Diagnosing a Real PLC Connection

When connecting to a live Allen-Bradley PLC, verify these points: