- Overview
- Common Conversion Scenarios
- Protocol Translation Patterns
- Multi-Protocol Gateway
- Data Transformation
- Bidirectional Conversion
- Performance Optimisation
- Error Handling
- Best Practices
- Next Steps
Overview
Protocol conversion is a core capability of the IndustryOS IoT Gateway, enabling interoperability between devices and systems using different communication protocols. The gateway acts as a translator, bridging incompatible protocols and enabling seamless data flow.
Common Conversion Scenarios
Scenario 1: Modbus to MQTT
Convert industrial Modbus devices to modern MQTT.
Source: Modbus RTU/TCP devices
Target: MQTT broker / IndustryOS
Benefits:
- Enable pub/sub messaging
- Add device discovery
- Implement real-time updates
- Reduce polling overhead
Configuration:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"modbus": {
"type": "tcp",
"host": "192.168.1.100",
"port": 502,
"devices": [
{
"deviceName": "Industrial-PLC",
"unitId": 1,
"telemetry": [
{"tag": "temperature", "address": 100}
]
}
]
}
}
Gateway automatically:
- Polls Modbus device
- Extracts data
- Publishes to MQTT topic
- Forwards to IndustryOS
Scenario 2: OPC-UA to REST
Expose OPC-UA data via RESTful API.
Source: OPC-UA server
Target: REST API consumers
Use Case:
- Web application access
- Third-party integration
- Cloud services
Implementation:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"opcua": {
"server": "opc.tcp://192.168.1.200:4840",
"mapping": [
{
"deviceNodePattern": "Root\\.Objects\\.Device1",
"deviceNamePattern": "Device1",
"attributes": [
{"key": "model", "path": "${ns=2;i=3}"}
],
"telemetry": [
{"key": "pressure", "path": "${ns=2;i=5}"}
]
}
]
}
}
Access via Request connector or platform API.
Scenario 3: BACnet to MQTT
Connect building automation to IoT platform.
Source: BACnet devices (HVAC, lighting)
Target: MQTT / IndustryOS
Benefits:
- Modern protocol for legacy BMS
- Cloud integration
- Mobile access
- Analytics capabilities
Configuration:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"bacnet": {
"interface": "192.168.1.10",
"devices": [
{
"deviceId": 1001,
"deviceName": "HVAC-Unit-1",
"objectsList": [
{
"objectType": "analogInput",
"objectId": 0,
"key": "temperature"
}
]
}
]
}
}
Scenario 4: Serial to Ethernet
Bridge serial devices to network.
Source: RS-232/RS-485 devices
Target: Ethernet network
Solution: Socket connector with custom protocol.
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"socket": {
"type": "tcp",
"host": "0.0.0.0",
"port": 9000,
"devices": [
{
"deviceName": "Serial-Device-${id}",
"converter": "CustomSerialConverter"
}
]
}
}
Protocol Translation Patterns
Pattern 1: Poll-to-Push
Convert polling protocols to event-driven.
Example: Modbus (polling) → MQTT (push)
1
2
Before: Client polls Modbus every 5 seconds
After: Gateway polls, publishes on change
Benefits:
- Reduced network traffic
- Real-time notifications
- Better scalability
Pattern 2: Request-Response to Pub-Sub
Transform synchronous to asynchronous.
Example: HTTP REST → MQTT
1
2
3
# REST endpoint receives data
# Gateway publishes to MQTT topic
# Multiple subscribers receive updates
Pattern 3: Binary to JSON
Convert binary protocols to JSON.
Example: Modbus registers → JSON telemetry
1
2
3
4
// Modbus: Register 100 = 0x09C4 (2500)
{
"temperature": 25.0 // After conversion
}
Pattern 4: Proprietary to Standard
Translate vendor protocols to standards.
Custom Converter:
1
2
3
4
5
6
7
8
9
10
11
12
13
class ProprietaryToMQTT:
def convert(self, data, metadata):
# Parse proprietary format
parsed = self._parse_vendor_protocol(data)
# Convert to standard format
return {
"deviceName": parsed["id"],
"telemetry": [
{"ts": parsed["timestamp"],
"values": parsed["measurements"]}
]
}
Multi-Protocol Gateway
Centralised Data Hub
1
2
3
4
5
Modbus Devices ───┬───────────────┐
OPC-UA Servers ───┤ Gateway ├───────────→ IndustryOS
BACnet Devices ───┤ (Protocol │ Platform
MQTT Sensors ───┤ Conversion) ├───────────→ Analytics
REST APIs ───┴───────────────┘ Dashboards
Configuration Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
connectors:
- name: "Modbus Connector"
type: "modbus"
configuration: "modbus.json"
- name: "OPC-UA Connector"
type: "opcua"
configuration: "opcua.json"
- name: "BACnet Connector"
type: "bacnet"
configuration: "bacnet.json"
- name: "MQTT Connector"
type: "mqtt"
configuration: "mqtt.json"
Data Transformation
Unit Conversion
Convert between measurement units:
1
2
3
4
5
6
7
8
9
10
11
{
"telemetry": [
{
"tag": "temperature",
"address": 100,
"type": "16int",
"multiplier": 0.1,
"unit": "celsius"
}
]
}
Data Normalisation
Standardise data formats:
1
2
3
4
5
6
7
8
9
10
11
class DataNormalizer:
def normalise(self, value, config):
# Apply scaling
scaled = value * config.get("scale", 1.0)
# Apply offset
offset = scaled + config.get("offset", 0.0)
# Round to precision
precision = config.get("precision", 2)
return round(offset, precision)
Timestamp Synchronisation
Align timestamps across protocols:
1
2
3
4
5
6
7
8
9
import time
def get_timestamp():
return int(time.time() * 1000) # Milliseconds
telemetry = {
"ts": get_timestamp(),
"values": {"temperature": 25.5}
}
Bidirectional Conversion
Uplink and Downlink
Uplink: Device → Platform
1
2
3
class UplinkConverter:
def convert(self, device_data, metadata):
return platform_format
Downlink: Platform → Device
1
2
3
class DownlinkConverter:
def convert(self, platform_command, metadata):
return device_format
Example: Modbus Write
RPC Request (MQTT/HTTP):
1
2
3
4
{
"method": "setValue",
"params": {"value": 100}
}
Converted to Modbus:
1
2
3
4
5
6
# Function 16: Write Multiple Registers
modbus_command = {
"function": 16,
"address": 1000,
"value": 100
}
Performance Optimisation
Reduce Protocol Overhead
Batch Requests:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"modbus": {
"devices": [
{
"telemetry": [
{
"tag": "batch_read",
"address": 100,
"objectsCount": 10 // Read 10 registers at once
}
]
}
]
}
}
Caching
Cache static data:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class CachingConverter:
def __init__(self, config):
self._cache = {}
self._cache_ttl = config.get("cacheTTL", 300)
def convert(self, data, metadata):
cache_key = self._get_cache_key(data)
if cache_key in self._cache:
if not self._is_expired(cache_key):
return self._cache[cache_key]
result = self._do_conversion(data)
self._cache[cache_key] = result
return result
Error Handling
Protocol Mismatch
Handle incompatible data types:
1
2
3
4
5
try:
value = int(data["temperature"])
except (ValueError, KeyError) as e:
logger.error(f"Invalid temperature data: {e}")
value = None # Or default value
Timeout Handling
Manage slow protocols:
1
2
3
4
5
6
7
{
"modbus": {
"timeout": 5,
"retries": 3,
"devices": [...]
}
}
Best Practices
Protocol Selection
- Use MQTT for real-time updates
- Use Modbus for industrial PLCs
- Use OPC-UA for manufacturing
- Use REST for web integration
- Use BACnet for building automation
Data Mapping
- Document conversion logic
- Validate data types
- Handle edge cases
- Test with real data
- Monitor conversion errors
Performance
- Batch operations when possible
- Use appropriate poll intervals
- Cache static data
- Monitor resource usage
- Optimise converter code
Next Steps
- Legacy System Integration
- Edge Data Collection
- Industrial Automation
- Connector Configuration