Overview
The AutomationDirect C-more CM5 series (including the CM5-T7W 7-inch widescreen model) is a full-featured HMI platform with native Ethernet and serial drivers for more than 100 PLC families, plus Modbus TCP/IP, Modbus RTU, and BACnet. The panel's Tag Name Database separates Internal tags (HMI-only scratchpad registers) from Device tags (registers bound to an external controller address). This distinction is the root cause of the most common beginner error: attempting to write to an Internal tag from a remote client and receiving a No connection could be made because the target machine actively refused it reply from Python's pylogix library.
This tutorial walks through configuring the CM5 as a Modbus TCP client that polls a Python pyModbusTCP server on the host PC. After commissioning, the same pattern can be used to display any process value (barcode, lot number, scale weight, vision system result) on a Dynamic Text object without requiring a physical PLC.
Prerequisites
| Item | Specification |
|---|---|
| HMI panel | C-more CM5-T7W (firmware 1.5x or later recommended) |
| Programming software | C-more Programming Software v6.x or later (free download from AutomationDirect) |
| Ethernet connection | 10/100 Base-T, panel IP on the same subnet as the host PC |
| Host PC | Python 3.8+ on Windows 10/11 or Linux |
| Required Python packages | pyModbusTCP>=0.2.0 |
| Default panel IP | 192.168.1.200 (CM5 ships DHCP-disabled with this static address) |
| Firewall rule | TCP port 502 must be open inbound on the host |
Reference: C-more Built-in Drivers overview (AutomationDirect video library) and the panel's User Manual / Installation Guide shipped with each unit.
Why pylogix Fails Against a CM5 Directly
pylogix speaks EtherNet/IP (CIP) and expects a Logix-family controller (CompactLogix, ControlLogix, MicroLogix 1100/1400) at the destination IP. The CM5 HMI does not run an EtherNet/IP server; its onboard protocols are listed in the table below.
| Protocol | Direction supported by CM5 | Typical use |
|---|---|---|
| EtherNet/IP (CIP) | Not supported as server | Use an Allen-Bradley PLC between PC and HMI |
| Modbus TCP/IP | Client only (master) | Poll external Modbus servers |
| Modbus RTU | Client only (master) | RS-232/485 devices |
| BACnet/IP | Client | Building automation |
| DirectLOGIC / Click / Productivity | Client | AutomationDirect PLCs (native K-sequence, Do-more, etc.) |
When the Python script opens a TCP socket to the panel's IP on port 44818 (EtherNet/IP) or 2222 (CSP), nothing is listening, so the OS returns a connection refused error. The fix is to flip the relationship: make the panel the client and put a Modbus TCP server on the PC.
Step 1 — Configure Modbus TCP in Protocol Manager
- Open the C-more project and select Setup → Protocol Manager (older firmware shows Panel Manager; both expose the same Modbus driver).
- Click Add and choose Modbus TCP/IP Client from the driver list.
- Assign the protocol to Port 1 (Ethernet) and configure the panel IP parameters: IP address, subnet mask, and gateway. The default IP 192.168.1.200 is acceptable for direct-to-PC links.
- Click PLC Interface Configuration → Add. Set the IP Address field to the host PC's address (e.g.,
192.168.1.24) and the Port to502. - Set the Timeout to
1000 ms and the Retries to3during commissioning. Lower the timeout once the network is stable to speed up object redraws. - Click OK and download the project to the panel.
Step 2 — Build Modbus-Mapped Tags in the Tag Name Database
The Tag Name Database is accessed from the Project Navigator pane. For every value the HMI must display, create a row with the columns below.
| Column | Value for barcode demo | Notes |
|---|---|---|
| Tag Name | Usr_TapeZone_Barcode |
Maximum 32 alphanumeric characters, no spaces |
| Data Type |
ASCII String (length 32) or UINT array |
Modbus does not support strings natively; use a holding-register array |
| Device Name | DEV001 |
Must match the name created in Protocol Manager |
| Address |
400001 (function code 03, holding register 0) |
Use the Modbus Address format the panel expects |
| Tag Type | Device |
Never Internal for external data |
| Read/Write | Read/Write |
Required if the HMI needs to acknowledge the data |
Create a second tag to drive the visibility trigger:
- Tag Name:
Usr_Show_TapeZone_Barcode - Data Type:
Boolean(mapped to a single coil or holding register bit) - Address:
000001(coil 0) or400100if you prefer holding registers
After these tags are committed, drop a Dynamic Text object on the screen, bind its Value Source to Usr_TapeZone_Barcode, and use the Visibility animation tied to Usr_Show_TapeZone_Barcode == 1.
Step 3 — Python pyModbusTCP Server
Install the package and run the example server. Port 502 is privileged on Linux; either run the script as root or rebind to 5020 and update the panel configuration to match.
# cm5_modbus_server.py
# Tested with pyModbusTCP 0.2.0, Python 3.10
from pyModbusTCP.server import ModbusServer
import time
server = ModbusServer("192.168.1.24", 502, no_block=True)
T1 = time.perf_counter()
bitValue = 0
try:
print("Start server...")
server.start()
print("Server is online on 192.168.1.24:502")
while True:
T2 = time.perf_counter()
if T2 - T1 >= 1.0:
T1 = T2
bitValue = 1 - bitValue
print("Holding reg[0] ->", bitValue)
# Holding register 0 maps to CM5 address 400001
server.data_bank.set_holding_registers(0, [bitValue])
# Optional: write a 4-char ASCII value to registers 10..11
# 'A1B2' packed as two 16-bit words, low byte first
server.data_bank.set_holding_registers(10, [0x3141, 0x3242])
except Exception as e:
print("Server error:", e)
server.stop()
print("Server is offline")
String handling on Modbus requires packing two ASCII bytes per 16-bit register. For a 32-character barcode you must reserve 16 consecutive holding registers, then unpack in the panel by mapping each word to a substring of an ASCII String tag whose length is set to 32.
Step 4 — Wiring the Dynamic Text and Visibility
- Insert a Dynamic Text object on the destination screen. Under Data, set the source to
Usr_TapeZone_Barcode. - Open Animations → Visibility. Set the trigger condition to
Usr_Show_TapeZone_Barcode == 1. - If you prefer a multi-state indicator, add a Multi-State Indicator whose states are sourced from the lookup text database. C-more's Message Database Data Logging workflow applies equally well for barcode events.
- Compile and download the project. The panel will begin polling the Python server immediately on power-up.
Verification
Confirm the link end-to-end with these checks.
| Step | Action | Expected result |
|---|---|---|
| 1 | Ping panel from PC | Reply from 192.168.1.200 in < 1 ms |
| 2 | Run Python server, watch console | "Server is online on 192.168.1.24:502" |
| 3 | From PC, run mbpoll -m tcp -t 3 -r 1 -c 1 192.168.1.24
|
Returns 0 or 1 (coil/holding state) |
| 4 | Trigger Usr_Show_TapeZone_Barcode from a screen pushbutton |
Dynamic Text appears with current barcode |
| 5 | Watch the panel's System Screen → Error Log | No Modbus timeout errors logged |
Troubleshooting Matrix
| Symptom | Likely cause | Corrective action |
|---|---|---|
| "Connection actively refused" from pylogix | pylogix uses EtherNet/IP; CM5 does not host CIP | Replace pylogix with pyModbusTCP, run a server, configure CM5 as Modbus client |
Tag shows ???? on screen |
Tag Type set to Internal in Tag Database | Change Tag Type to Device and assign a valid Modbus address |
| Intermittent Timeout Error #E-0019 on panel | PC firewall or wrong IP | Allow port 502 inbound; verify PLC Interface IP matches server IP |
| Server bound but panel cannot read | Subnet mismatch | Confirm both nodes share subnet mask (e.g., 255.255.255.0); confirm gateway if cross-router |
| Port 502 "Permission denied" on Linux | Privileged port | Bind to >1024 and update Protocol Manager port to match |
| String displays reversed or garbled | Byte order mismatch (big-endian vs little-endian) | Swap nibbles when packing; CM5 expects low-byte-first for ASCII |
| Project downloads but tags stay at zero | Wrong device number in Protocol Manager | Ensure Device Name in Tag Database matches the configured PLC interface |
Performance and Limits
- The CM5 polls up to 32 Modbus tags per screen by default; additional tags may slow screen redraws.
- Recommended minimum poll period is 100 ms per tag; below this, the panel's internal queue saturates.
- String tags occupy 1 Modbus register per 2 ASCII characters plus 1 length register when using the panel's ASCII String type.
- Wire the host PC with a static IP (DHCP reservations fail-over) to avoid breaking the polling loop when leases expire.
FAQ
Why does pylogix fail to connect to a C-more CM5-T7W?
The CM5 does not host an EtherNet/IP (CIP) server. pylogix sends CIP messages to TCP port 44818, which the panel does not listen on, producing a connection refused error. Configure the panel as a Modbus TCP client and use pyModbusTCP instead.
Can the CM5 act as a Modbus TCP server so my Python code can write to it directly?
No. The C-more CM5 firmware exposes Modbus only in client (master) mode. To write to the panel from a PC you must run a Modbus server on the PC (for example pyModbusTCP) and let the panel poll it.
How do I map a Python string into a CM5 Dynamic Text object?
Pack two ASCII bytes into each 16-bit Modbus holding register (low byte first), reserve enough consecutive registers to cover the string length, then create a CM5 tag of type ASCII String with the matching register count. Bind the Dynamic Text to that tag.
What Modbus address should I enter in the CM5 Tag Name Database?
Use the panel's standard notation: holding registers are entered as 4xxxxx starting at 400001, coils as 0xxxxx starting at 000001. The trailing digits map 1:1 to register numbers on the wire.
Why does my Dynamic Text object stay hidden even though the trigger coil is 1?
Confirm the visibility trigger tag points to the same Modbus address your Python server is writing, that the tag's Tag Type is Device (not Internal), and that the panel is not logging Modbus timeout errors in its system error screen.