Modbus TCP
Pull coils, discrete inputs, and holding/input registers from Modbus TCP devices into AnyLog using run plc client.
AnyLog can act as a Modbus TCP client (over hostname and port, typically port 502). Data is read on a
schedule and streamed into your local operator database as JSON, using the same run plc client pattern as
OPC-UA and EtherNet/IP.
Prerequisites
| Requirement | Notes |
|---|---|
pymodbus |
Must be installed in the AnyLog runtime environment. |
Declare the target DBMS before streaming, for example:
connect dbms new_company where type = sqlite
Connection and map
Modbus uses hostname and port (not url). device_id is the Modbus PDU unit id (often 0 or 1 on TCP). map is a JSON array of points; each object must include a name (column / logical label) and exactly one address field:
| Key | Meaning |
|---|---|
coil |
Coil (0-based address) |
input |
Discrete input |
inputRegister |
Input register (single address or list for blocks) |
register |
Holding register (single address or list for blocks) |
topic is not supported on Modbus run plc client commands.
One-shot read
<get plc values where type = modbus and
hostname = 192.168.1.72 and
port = 1502 and
device_id = 1 and
map = [{"name":"sensor_1","register":0}]
>
Alias: get modbus values (same keywords).
Continuous ingest — wide table (default)
With table = ... and dbms, all points from map land in one table. Each poll inserts one row; every object in map is one column: the map name is the column name, and that column stores the value read for that point.
<run plc client where type = modbus and
hostname = 192.168.1.72 and
port = 1502 and
device_id = 1 and
frequency = 5 and
name = my_mb and
dbms = new_company and
table = sensors and
map = [{"name":"temperature","register":0}]
>
Continuous ingest — dynamic tables (dynamic = true)
Omit table and omit namespace for plain dynamic ingest. Each object in map is written to its own table. The table name is derived from the client name and the map name (for example, fdev10_outside_temperature when name = fdev10 and the map entry’s name is outside_temperature). Each row includes timestamp, tag, and value.
<run plc client where type = modbus and
hostname = 192.168.1.72 and
port = 1502 and
device_id = 1 and
frequency = 5 and
name = fdev10 and
dbms = new_company and
dynamic = true and
map = [{"name":"outside_temperature","inputRegister":1}]
>
Dynamic ingest with UNS (namespace + master_node)
With dynamic = true, you can add a Unified Namespace path and a master node so Modbus ingest is registered in the UNS alongside your policies and DBMS. namespace requires master_node = [ip:port] for policy updates.
Example (abbreviated):
run plc client where type = modbus and
hostname = 192.168.1.72 and
port = 1502 and
device_id = 1 and
frequency = 5 and
name = fdev11 and
dbms = new_company and
dynamic = true and
master_node = 192.168.1.88:32048 and
namespace = FA9/MID9/DEVICE9 and
map = [{"name":"desk_lamp","coil":0}]
Table names follow the same pattern as plain dynamic = true (client name plus map name, e.g. fdev11_desk_lamp for the example above). Under UNS, the read value is usually stored in a column named like the tag—the map name (here desk_lamp), not a generic value column.
With namespace, table and column layout follow UNS policies. namespace and master_node drive how
tables are registered in the UNS. See Unified Namespace for background.
Command keywords (summary)
| Keyword | Required / notes |
|---|---|
type |
modbus |
hostname, port |
Modbus TCP target |
device_id |
PDU unit id |
frequency |
Poll interval |
name |
Unique client name |
dbms |
Target DBMS |
table |
Wide-table ingest; omit with dynamic = true |
dynamic |
true for per-map tables or UNS |
map |
JSON array of points |
namespace |
UNS path (Modbus + dynamic = true only) |
master_node |
Required when namespace is set |