PLC Relay
Configure PLC Relay to read and write PLC tags over Allen-Bradley, Modbus TCP, or Siemens S7.
PLC Relay is an edge container service that provides an HTTP API for reading and writing PLC tags. You configure it through the Deployment Manager UI by selecting a protocol, entering connection details, and defining tags.
Supported Protocols
When adding or editing a PLC Relay service, you select one of three protocols. Each protocol has its own connection settings and tag format.
Protocol
PLC_DRIVER
PLCs
Default Port
Allen-Bradley (EtherNet/IP)
allen_bradley
CompactLogix, ControlLogix, Micro800
44818
Modbus TCP
modbus
Any Modbus TCP device
502
Siemens S7
siemens_s7
S7-300, S7-400, S7-1200, S7-1500
102
Switching protocols clears all configured tags because tag address formats are not interchangeable between protocols. The UI will prompt for confirmation before applying the change.
Connection Settings
PLC Address
The address format depends on the selected protocol:
Allen-Bradley: IP or hostname, optionally followed by
/slot(e.g.192.168.1.100/0) or a full CIP routing path.Modbus TCP: IP or hostname, with optional
:port(e.g.192.168.1.100:502). Also requires a Unit ID (0-255) and Word Order (big or little) for 32-bit values.Siemens S7: IP or hostname, with optional
:port(e.g.192.168.1.100:102). Also requires Rack (0-7) and Slot (0-31).
Simulation Mode
When enabled, PLC Relay uses an in-memory simulator instead of connecting to a real PLC. All API operations work normally, but values are stored in memory. This is useful for testing without hardware.
Tag Configuration
Tags define the PLC data points accessible through the API. Each tag has a name, data type, writable flag, and optional description.
Data Types
BOOL
Boolean
true / false
INT
16-bit signed integer
-32,768 to 32,767
DINT
32-bit signed integer
-2,147,483,648 to 2,147,483,647
REAL
32-bit floating point
IEEE 754
Tag Name Formats
Tag names match the PLC program and are case-sensitive.
Simple
TagName
Program-scoped
Program:MainProgram.TagName
Array element
TagName[0]
UDT member
MyUDT.Member
Format: {area}:{address} where address is a non-negative integer.
coil
BOOL
Writable
coil:0
discrete
BOOL
Read-only
discrete:5
holding
INT, DINT, REAL
Writable
holding:100
input
INT, DINT, REAL
Read-only
input:200
Data Block format: DB{n}.DB[XWD]{byte}[.{bit}]
Area format: [MIQEA][WD]?{byte}[.{bit}]
DB1.DBX0.0
BOOL
Bit 0 of byte 0 in Data Block 1
DB1.DBW0
INT
16-bit word in DB1
DB1.DBD0
DINT or REAL
32-bit double-word in DB1
M0.0
BOOL
Merker bit
I0.0 / Q0.0
BOOL
Process input/output bit
MW0 / MD0
INT / DINT or REAL
Merker word / double-word
For S7-1200/1500: enable PUT/GET in TIA Portal and disable optimized block access on accessed DBs.
Web Dashboard
PLC Relay includes a built-in web dashboard for monitoring tag values in real time. Once the service is running, access it at http://<device-ip>:8007.
The dashboard also hosts interactive Swagger documentation at /docs and a visual config builder at /static/config-builder.html.
HTTP API
The API reads and writes the configured tags over HTTP, so a pipeline can exchange PLC data without speaking Allen-Bradley EtherNet/IP, Modbus TCP, or Siemens S7 directly. Base URL is http://<device-ip>:8007, and the API is unauthenticated. See Services for the rules shared by all on-device service APIs.
Tags come from the PLC_TAGS environment variable on the service and cannot be created or changed through the API. Only values can be written, and only for tags configured as writable.
Read Before You Trust the Status Code
A request that reaches the service but fails at the PLC returns 200. Check the body:
/readreturnsvalue: nullwitherrorpopulated./writereturnssuccess: falsewitherrorpopulated./healthzreturnsplc_connected: false.
Genuine 4xx responses mean the request itself was wrong: 404 for a tag that is not configured, 403 for a tag configured as read-only, 400 for an empty batch or a duplicate tag name in a write batch, 422 for a body or query parameter that fails validation.
Health and Validation
/healthz also reports the active driver, whether the relay is in live or simulation mode, and the latest tag validation summary. Validation compares each configured tag against the PLC and reports it as ok, not_found, type_mismatch, or not_validated.
Returns service status, PLC connection state, the active driver and mode, and the latest tag validation summary. Returns 200 with plc_connected: false when the PLC is unreachable, so check the field rather than the status code.
Service status
Service status, healthy or unhealthy
Whether the PLC is connected
Number of configured tags
Active PLC driver
Whether the relay is talking to a real PLC or the in-memory simulator
Configured PLC address
GET /healthz HTTP/1.1
Host: device-ip:8007
Accept: */*
Service status
{
"status": "healthy",
"plc_connected": true,
"tag_count": 3,
"plc_driver": "allen_bradley",
"mode": "live",
"plc_ip": "192.168.1.100/0",
"tag_validation": {
"validated": true,
"total": 3,
"ok": 3,
"not_found": 0,
"type_mismatch": 0,
"not_validated": 0,
"tags": {}
}
}Re-run validation after a PLC program change or a reconnection:
Validates every configured tag against the PLC, checking that it exists and that its data type matches the configuration. Useful after a PLC program change or a reconnection. Returns a summary with validated: false and zeroed counts when no validation results are available.
Validation summary
Whether validation has been performed
Total number of configured tags
Tags that passed validation
Tags not found on the PLC
Tags whose PLC type does not match the configuration
Tags not yet validated
Service not initialized
POST /validate HTTP/1.1
Host: device-ip:8007
Accept: */*
{
"validated": true,
"total": 1,
"ok": 1,
"not_found": 1,
"type_mismatch": 1,
"not_validated": 1,
"tags": {
"ANY_ADDITIONAL_PROPERTY": {
"status": "ok",
"configured_type": "text",
"actual_type": "text",
"detail": "text"
}
}
}Tag Definitions
Tag names are PLC addresses in the format for the active driver, described in Tag Name Formats.
Returns the tag schema as defined by the PLC_TAGS environment variable.
Tag definitions
Number of tags
GET /schema HTTP/1.1
Host: device-ip:8007
Accept: */*
Tag definitions
{
"tags": [
{
"name": "text",
"type": "BOOL",
"description": "",
"writable": true
}
],
"count": 1
}Read and Write Values
Returns the current value of every configured tag, along with connection state.
Current values for all tags
Service not initialized
GET /all_tags HTTP/1.1
Host: device-ip:8007
Accept: */*
{
"tags": [
{
"name": "text",
"type": "BOOL",
"description": "text",
"writable": true,
"value": true,
"last_updated": "2026-01-01T00:00:00.000Z",
"error": "text",
"validation_status": "ok",
"validation_detail": "text"
}
],
"count": 1,
"plc_connected": true
}Reads one tag by name. A read that reaches the service but fails at the PLC returns 200 with error populated and value null, so check error as well as the status code.
Name of the tag to read, as configured in PLC_TAGS.
Station1.CycleCountTag value
Tag data type. INT is a 16-bit signed integer (-32,768 to 32,767), DINT a 32-bit signed integer (-2,147,483,648 to 2,147,483,647), and REAL a 32-bit float.
Current value, null when the read failed
Read error, null on success
Unknown tag
Request failed validation
Service not initialized
GET /read?tag=text HTTP/1.1
Host: device-ip:8007
Accept: */*
{
"name": "Station1.CycleCount",
"type": "DINT",
"description": "Total cycle count",
"writable": true,
"value": 42,
"last_updated": "2025-01-15T12:00:00+00:00",
"error": null,
"validation_status": "ok",
"validation_detail": null
}Writes one value to a configured writable tag. A write that reaches the PLC and fails there returns 200 with success: false and error populated.
Tag name to write
Value to write
Write result
Value written, null when the write failed
Tag is configured as not writable
Unknown tag
Request failed validation
Service not initialized
POST /write HTTP/1.1
Host: device-ip:8007
Content-Type: application/json
Accept: */*
Content-Length: 41
{
"name": "Station1.CycleCount",
"value": 42
}{
"name": "text",
"value": true,
"success": true,
"error": "text"
}Batch Operations
Both batch endpoints validate as a unit before anything runs, so an unknown tag rejects the whole request rather than returning partial results.
/write_batch additionally rejects a batch that names the same tag twice, since keeping only the last value for a repeated name would silently drop the earlier writes. /read_batch accepts duplicates and returns one result per entry, in the order you sent them.
PLC failures that happen after validation are reported per entry in write_batch's results, with success_count and error_count summarizing the batch.
Reads several tags in one request. Every name is checked before any read runs, so an unknown tag fails the whole request with 404 rather than returning partial results.
Tag names to read
Tag values
Number of tags read
Empty tag list
Unknown tag in the list
Request failed validation
Service not initialized
POST /read_batch HTTP/1.1
Host: device-ip:8007
Content-Type: application/json
Accept: */*
Content-Length: 55
{
"tags": [
"Station1.PartPresent",
"Station1.CycleCount"
]
}{
"tags": [
{
"name": "text",
"type": "BOOL",
"description": "text",
"writable": true,
"value": true,
"last_updated": "2026-01-01T00:00:00.000Z",
"error": "text",
"validation_status": "ok",
"validation_detail": "text"
}
],
"count": 1
}Writes several tags in one request. The whole batch is validated first: an empty list, a duplicate tag name, an unknown tag, or a tag that is not writable rejects the request before any write happens. Duplicates are rejected rather than collapsed, since silently keeping the last value for a name would drop the earlier writes.
Individual PLC failures after validation are reported per entry in results, with success_count and error_count summarizing the batch.
Per-write results
Empty writes list or duplicate tag name in the batch
A tag in the batch is configured as not writable
Unknown tag in the batch
Request failed validation
Service not initialized
POST /write_batch HTTP/1.1
Host: device-ip:8007
Content-Type: application/json
Accept: */*
Content-Length: 96
{
"writes": [
{
"name": "Station1.CycleCount",
"value": 42
},
{
"name": "Station1.ResetCmd",
"value": true
}
]
}{
"results": [
{
"name": "text",
"value": true,
"success": true,
"error": "text"
}
],
"success_count": 1,
"error_count": 1
}CLI
The plc-cli tool gives an interactive terminal interface for reading and writing tags. Use it for debugging and quick operations when the web dashboard is not reachable. It is a local client running inside the container against the same HTTP API the dashboard uses.
R
Read all tag values
T
Read a single tag, selected from a list
W
Write a tag, selected from the writable tags
S
Show the tag schema
H
Show detailed health status
V
Run tag validation against the PLC
Enter
Refresh the display
Q
Quit
Environment Variables
The Configure modal writes these for you. Edit them directly only when a deployment is managed by hand. See Update Device Configuration.
PLC_DRIVER
none
allen_bradley, modbus, or siemens_s7
PLC_IP
none
PLC address in the format for the selected driver
PLC_TAGS
none
Tag definitions as JSON. The config builder at /static/config-builder.html generates this
SIMULATION_MODE
off
Use the in-memory simulator instead of a real PLC
LOG_LEVEL
INFO
Logging verbosity: DEBUG, INFO, WARNING, or ERROR
Driver-specific settings:
Modbus
MODBUS_UNIT_ID
0 to 255
1
Modbus
MODBUS_WORD_ORDER
big or little
big
Siemens S7
S7_RACK
0 to 7
0
Siemens S7
S7_SLOT
0 to 31
1
Connection Monitoring
The device page shows a live PLC Relay status card with the current connection state, the active protocol, and the latest tag values. When the relay cannot reach the PLC, the card displays an unreachable banner.
To be notified when a relay loses connectivity, add a "PLC Disconnected" alert from the device's "Device Alerts" tab. See Set up Device Alerts.
Troubleshooting
"PLC not connected" (Allen-Bradley)
Verify PLC address format (IP/Slot), check port 44818 is reachable
"PLC not connected" (Modbus)
Check IP/port (default 502) and verify Unit ID matches the device
"PLC not connected" (Siemens S7)
Check IP/port (default 102), rack, and slot values; for S7-1200/1500 enable PUT/GET and disable optimized block access
"Function refused" (Siemens S7)
PUT/GET disabled in TIA Portal, or optimized block access enabled on the target DB
REAL value reads as garbage (Modbus)
Try the opposite Word Order (big vs. little)
Validation shows NOT_FOUND
Check the PLC program for the exact tag name (case-sensitive)
Last updated
Was this helpful?