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
| Scenario | Recommended approach |
|---|---|
| Devices behind a firewall / NAT | Edge agent (pushes outbound) |
| Cloud-accessible OPC-UA / Modbus servers | Direct ingestion |
| Unreliable network to cloud | Edge agent (offline buffering) |
| Quick proof-of-concept | Direct ingestion |
| Hundreds of devices at one site | Edge 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.ioto 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"}
]
}'
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
| Mode | Description | Recommended |
|---|---|---|
None | No encryption or signing | Dev/testing only |
Sign | Messages are signed but not encrypted | Trusted networks |
SignAndEncrypt | Full signing and encryption | Production |
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
| Type | Modbus function | Address range | Access |
|---|---|---|---|
coil | FC01 | 00001–09999 | Read/Write |
discrete_input | FC02 | 10001–19999 | Read only |
input | FC04 | 30001–39999 | Read only |
holding | FC03 | 40001–49999 | Read/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
- Check the source status: is
enabledset totrue? - Verify tag mappings exist for OPC-UA sources
- Confirm the machine ID matches a registered machine
- 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
- Edge Agent Setup , for devices behind firewalls
- Sensor Data API , query and aggregate your ingested data
- Alert Rules , set up threshold monitoring on your metrics