Skip to main content

Direct Ingestion: OPC-UA & Modbus

Haltless can poll your industrial devices directly from the cloud , no edge agent required. This guide walks through setting up OPC-UA and Modbus TCP direct ingestion connections.

When to use direct ingestion

ScenarioRecommended approach
Devices behind a firewall / NATEdge agent (pushes outbound)
Cloud-accessible OPC-UA / Modbus serversDirect ingestion
Unreliable network to cloudEdge agent (offline buffering)
Quick proof-of-conceptDirect ingestion
Hundreds of devices at one siteEdge agent (reduces cloud polling load)

Direct ingestion is ideal when your PLCs or OPC-UA servers are reachable from the internet (e.g., via VPN or public IP) and you want the simplest possible setup.

Prerequisites

  • A Haltless account with an active subscription
  • At least one machine registered in your tenant
  • Network connectivity from api.haltless.io to your device's IP and port
  • For OPC-UA: server URL and node IDs for the tags you want to monitor
  • For Modbus TCP: device IP, port, unit ID, and register addresses

OPC-UA direct ingestion

Step 1: Create the connection

curl -X POST "https://api.haltless.io/api/v1/ingest/opcua/sources" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"machine_id": "MACHINE_UUID",
"endpoint_url": "opc.tcp://203.0.113.10:4840",
"security_mode": "SignAndEncrypt",
"security_policy": "Basic256Sha256",
"auth_type": "username",
"username": "opcuser",
"password": "securepass",
"poll_interval_seconds": 5,
"node_ids": [
"ns=2;s=Temperature",
"ns=2;s=Pressure",
"ns=2;s=Vibration"
],
"enabled": true
}'

Step 2: Map tags to metrics

After creating the source, map OPC-UA node IDs to Haltless metric names:

curl -X POST "https://api.haltless.io/api/v1/sensor-data/tag-mappings" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"machine_id": "MACHINE_UUID",
"mappings": [
{"tag": "ns=2;s=Temperature", "metric_name": "temperature", "unit": "celsius"},
{"tag": "ns=2;s=Pressure", "metric_name": "pressure", "unit": "bar"},
{"tag": "ns=2;s=Vibration", "metric_name": "vibration", "unit": "mm_s"}
]
}'
tip

Use POST /sensor-data/tag-mappings/auto-map to let the AI engine suggest metric names and units automatically based on your OPC-UA node IDs.

Step 3: Verify data flow

Wait for one poll interval, then check for readings:

curl "https://api.haltless.io/api/v1/sensor-data/latest?machine_id=MACHINE_UUID" \
-H "Authorization: Bearer YOUR_TOKEN"

Security modes

ModeDescriptionRecommended
NoneNo encryption or signingDev/testing only
SignMessages are signed but not encryptedTrusted networks
SignAndEncryptFull signing and encryptionProduction

Node ID formats

OPC-UA supports multiple node ID formats:

ns=2;s=Temperature # String identifier
ns=2;i=1001 # Numeric identifier
ns=2;g=xxxxxxxx-xxxx # GUID identifier

Modbus TCP direct ingestion

Step 1: Create the connection

curl -X POST "https://api.haltless.io/api/v1/ingest/modbus/sources" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"machine_id": "MACHINE_UUID",
"host": "203.0.113.20",
"port": 502,
"unit_id": 1,
"poll_interval_seconds": 10,
"registers": [
{
"address": 40001,
"register_type": "holding",
"data_type": "float32",
"metric_name": "temperature",
"unit": "celsius",
"scale": 1.0,
"offset": 0.0
},
{
"address": 40003,
"register_type": "holding",
"data_type": "uint16",
"metric_name": "rpm",
"unit": "rpm",
"scale": 1.0,
"offset": 0.0
}
],
"enabled": true
}'

Step 2: Verify data flow

curl "https://api.haltless.io/api/v1/sensor-data/latest?machine_id=MACHINE_UUID" \
-H "Authorization: Bearer YOUR_TOKEN"

Register types

TypeModbus functionAddress rangeAccess
coilFC0100001–09999Read/Write
discrete_inputFC0210001–19999Read only
inputFC0430001–39999Read only
holdingFC0340001–49999Read/Write

Data types and scaling

Raw Modbus registers are 16-bit values. Use the data_type, scale, and offset fields to convert to engineering units:

final_value = (raw_value × scale) + offset

Supported data types: uint16, int16, uint32, int32, float32, float64

For multi-register types (uint32, float32, float64), Haltless reads consecutive registers starting at the specified address.

Managing connections

List all sources

# OPC-UA sources
curl "https://api.haltless.io/api/v1/ingest/opcua/sources" \
-H "Authorization: Bearer YOUR_TOKEN"

# Modbus sources
curl "https://api.haltless.io/api/v1/ingest/modbus/sources" \
-H "Authorization: Bearer YOUR_TOKEN"

Update a source

curl -X PUT "https://api.haltless.io/api/v1/ingest/opcua/sources/{source_id}" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"poll_interval_seconds": 10, "enabled": true}'

Delete a source

curl -X DELETE "https://api.haltless.io/api/v1/ingest/opcua/sources/{source_id}" \
-H "Authorization: Bearer YOUR_TOKEN"

Troubleshooting

Connection refused

  • Verify the device IP and port are reachable from the internet
  • Check firewall rules , Haltless cloud needs inbound access to your device
  • For OPC-UA, confirm the endpoint URL matches exactly (including port)

Authentication failed

  • OPC-UA: verify username/password and that the security policy matches the server's configuration
  • Modbus: ensure the correct unit_id (slave address) is specified

No data appearing

  1. Check the source status: is enabled set to true?
  2. Verify tag mappings exist for OPC-UA sources
  3. Confirm the machine ID matches a registered machine
  4. Check the poll interval , data appears after the first poll cycle

Stale or duplicate readings

  • Ensure only one ingestion method is active per machine (don't run both an edge agent and direct ingestion for the same tags)
  • Verify timestamps on the device are synchronized (NTP recommended)

Next steps