Or: How I Learned to Stop Worrying and Love Industrial IoT
By Patrick Ryan, CTO @ Fireball Industries
"Making industrial automation slightly less painful since whenever I started this company"
Look, I'm not saying this OPC UA Server is over-engineered, but it supports 9 industrial protocols simultaneously. That's right, NINE. Because apparently "just use OPC UA" wasn't enterprise-y enough for 2026.
Is it overkill? Absolutely. Will it save your bacon when some legacy PLC from 1997 insists on MODBUS? Also yes.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β OPC UA Server Core (Port 4840) β
β Tag Simulation + Real-time Updates β
β β
βββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββ
β
β PublisherManager orchestrates all protocols
β
βββββββββββββββββββββ΄ββββββββββββββββββββ
β β
βΌ βΌ
βββββββββββββββ ββββββββββββββββββ
β INBOUND β β OUTBOUND β
β (Server) β β (Clients) β
βββββββββββββββ ββββββββββββββββββ
β β
β β
βββΊ OPC UA Server βββΊ OPC UA Client β NEW
β (Clients connect to us) β (We push to servers)
β Port: 4840 β β Ignition
β β β Historians
β β β Cloud platforms
β β
βββΊ MODBUS TCP Server βββΊ MQTT Publisher
β (PLCs poll us) β (We publish to broker)
β Port: 502 β β Cloud (AWS/Azure)
β Registers: 0-1000 β β Node-RED
β β β IoT platforms
β β
βββΊ REST API Server βββΊ Sparkplug B Publisher
β (HTTP clients query us) β (We publish to broker)
β Port: 5001 β β Ignition Edge (native)
β GET/POST endpoints β β Cirrus Link
β β
βββΊ WebSocket Server βββΊ Apache Kafka Producer
β (Browsers connect to us) β (We publish to topics)
β Port: 9001 β β Data lakes
β Real-time push β β Stream processing
β β
β βββΊ AMQP Publisher
β (We publish to exchange)
β β RabbitMQ
β β Enterprise bus
β
βββΊ Total: 4 Server Modes βββΊ Total: 5 Client Modes
The Scorecard of Our Protocol Addiction
| # | Protocol | Type | Port | Direction | Use Case | Millennial Translation |
|---|---|---|---|---|---|---|
| 1 | OPC UA Server | Server | 4840 | β Inbound | SCADA systems connect | "Y'all can read my data" |
| 2 | OPC UA Client β | Client | N/A | β Outbound | Push to Ignition, historians | "I'm sliding into your DMs" |
| 3 | MQTT | Client | N/A | β Outbound | IoT/cloud brokers | "Publishing my thoughts online" |
| 4 | Sparkplug B | Client | N/A | β Outbound | Ignition Edge native | "Speaking Ignition's language" |
| 5 | Apache Kafka | Producer | N/A | β Outbound | Enterprise streaming | "Screaming into the void (at scale)" |
| 6 | AMQP | Publisher | N/A | β Outbound | RabbitMQ messaging | "Enterprise-grade texting" |
| 7 | WebSocket | Server | 9001 | β Inbound | Real-time browsers | "Live streaming my data" |
| 8 | REST API | Server | 5001 | β Inbound | HTTP GET/POST | "The API everyone understands" |
| 9 | MODBUS TCP | Server | 502 | β Inbound | Legacy PLCs poll | "Talking to grandpa's PLC" |
| 10 | GraphQL | Server | 5002 | β Inbound | Modern query interface | "REST but you pick the fields" |
| 11 | InfluxDB | Client | N/A | β Outbound | Time-series database | "Remembering everything forever" |
| 12 | Alarms | Monitor | N/A | β Outbound | Notifications | "Screaming when things break" |
Tag Update: Temperature = 25.5Β°C
β
βββΊ OPC UA Server (Port 4840)
β βββΊ UaExpert reads value
β
βββΊ OPC UA Client β
β βββΊ Writes to Ignition server (ns=2;s=Gateway/Temperature)
β βββΊ Writes to Historian (ns=1;s=Plant/Temp)
β βββΊ Writes to Cloud server (ns=1;s=Devices/Edge001/Temp)
β
βββΊ MQTT Publisher
β βββΊ Publishes to industrial/opcua/Temperature
β βββΊ Node-RED subscribes
β βββΊ AWS IoT Core receives
β βββΊ Azure IoT Hub receives
β
βββΊ Sparkplug B Publisher
β βββΊ Publishes DDATA message
β βββΊ Ignition MQTT Engine receives
β
βββΊ Apache Kafka Producer
β βββΊ Publishes to industrial-data topic
β βββΊ Kafka Streams processes
β βββΊ Data lake ingests
β
βββΊ AMQP Publisher
β βββΊ Publishes to industrial.data exchange
β βββΊ RabbitMQ routes to queues
β
βββΊ WebSocket Server (Port 9001)
β βββΊ Broadcasts to connected browsers
β βββΊ Dashboard updates in real-time
β
βββΊ REST API (Port 5001)
β βββΊ Stores in memory
β βββΊ Responds to HTTP requests
β
βββΊ GraphQL API (Port 5002)
βββΊ Stores in memory
βββΊ Responds to GraphQL queries
βββΊ GraphiQL IDE available
β
βββΊ InfluxDB Publisher
βββΊ Writes to time-series database
βββΊ Grafana visualizes data
βββΊ Historical analysis available
β βββΊ GET /api/tags/Temperature returns value
β
βββΊ MODBUS TCP Server (Port 502)
βββΊ Stores in registers 0-1 (float = 2 registers)
βββΊ PLC polls holding registers
Goal: Complete Ignition ecosystem integration
Your Server
βββΊ OPC UA Client β Ignition OPC UA Server (write tags)
βββΊ Sparkplug B β Ignition MQTT Engine (SCADA protocol)
Ignition connects via:
βββΊ OPC UA Client β Your OPC UA Server (read tags)
βββΊ Designer β Your REST API (monitoring)
Configuration:
{
"publishers": {
"opcua_client": {
"enabled": true,
"servers": [{
"url": "opc.tcp://ignition:4841",
"namespace": 2,
"base_node": "ns=2;s=Gateway/"
}]
},
"sparkplug_b": {
"enabled": true,
"broker": "ignition",
"port": 1883,
"group_id": "Sparkplug B Devices"
}
}
}Goal: Log to multiple historians for redundancy
Your Server
βββΊ OPC UA Client
β βββΊ Primary Historian (OSIsoft PI)
β βββΊ Backup Historian (Canary)
βββΊ Kafka Producer β Enterprise data lake
Configuration:
{
"publishers": {
"opcua_client": {
"enabled": true,
"servers": [
{
"url": "opc.tcp://pi-server:4840",
"name": "Primary PI",
"node_mapping": {
"Temperature": "ns=1;s=Plant.Area1.Temp"
}
},
{
"url": "opc.tcp://canary:4840",
"name": "Backup Canary"
}
]
},
"kafka": {
"enabled": true,
"topic": "historian-backup"
}
}
}Goal: Push from factory floor to cloud platforms
Factory Floor
β
βββΊ Your Server (Edge Gateway)
βββΊ OPC UA Client β Cloud OPC UA Server
βββΊ MQTT β AWS IoT Core
βββΊ Kafka β Cloud Kafka Cluster
βββΊ WebSocket β Cloud dashboard
Configuration:
{
"publishers": {
"opcua_client": {
"enabled": true,
"servers": [{
"url": "opc.tcp://cloud.company.com:4841",
"username": "edge-device-001",
"password": "${CLOUD_PASSWORD}"
}]
},
"mqtt": {
"enabled": true,
"broker": "mqtt.cloud.com",
"port": 8883,
"use_tls": true
}
}
}Goal: Bridge modern and legacy systems
Modern Systems
βββΊ Your OPC UA Server β SCADA reads via OPC UA
βββΊ Your REST API β Web dashboard reads via HTTP
Legacy Systems
βββΊ Your MODBUS TCP Server β Old PLC polls via MODBUS
Configuration:
{
"publishers": {
"modbus_tcp": {
"enabled": true,
"port": 502,
"register_mapping": {
"Temperature": {"register": 0, "type": "float"}
}
},
"rest_api": {
"enabled": true,
"port": 5001
}
}
}Goal: Local testing with all protocols
Your Server (localhost)
βββΊ OPC UA Server (4840) β UaExpert connects
βββΊ OPC UA Client β Test server (4841)
βββΊ MQTT β Local Mosquitto (1883)
βββΊ WebSocket (9001) β Browser connects
βββΊ REST API (5001) β Postman tests
βββΊ MODBUS TCP (502) β QModMaster polls
Configuration:
{
"publishers": {
"opcua_client": {"enabled": true},
"mqtt": {"enabled": true},
"websocket": {"enabled": true},
"rest_api": {"enabled": true},
"modbus_tcp": {"enabled": true}
}
}β Use when:
- Pushing to Ignition's OPC UA server
- Writing to historians (PI, Canary)
- Edge-to-cloud OPC UA connectivity
- Data replication to multiple OPC UA servers
- Centralized OPC UA server aggregation
β Don't use when:
- Need publish/subscribe (use MQTT instead)
- Need high-throughput streaming (use Kafka)
- Target doesn't support OPC UA
β Use when:
- IoT cloud platforms (AWS IoT, Azure IoT)
- Node-RED workflows
- Lightweight messaging
- Publish/subscribe needed
- Mobile app connectivity
β Don't use when:
- Need guaranteed delivery (use AMQP)
- Need high throughput (use Kafka)
- Target expects OPC UA
β Use when:
- Ignition Edge (primary use case)
- Need birth/death certificates
- Need store-and-forward
- SCADA-specific features needed
β Don't use when:
- Target doesn't support Sparkplug B
- Standard MQTT is sufficient
β Use when:
- High-throughput streaming
- Data lake ingestion
- Stream processing pipelines
- Enterprise microservices
- Event sourcing
β Don't use when:
- Simple messaging (use MQTT)
- Request/response needed (use REST)
- Low-volume data
β Use when:
- Legacy PLCs need to poll data
- SCADA systems expect MODBUS
- Industrial HMIs use MODBUS
- Vendor tools require MODBUS
β Don't use when:
- Modern protocols available
- Need event-driven (MODBUS is poll-based)
β Use when:
- Web applications
- Mobile apps
- Simple HTTP clients
- Periodic polling acceptable
- No persistent connection needed
β Don't use when:
- Need real-time push (use WebSocket)
- High-frequency updates (overhead)
| Protocol | Latency | Throughput | CPU Usage | Best For |
|---|---|---|---|---|
| OPC UA Server | 5-20ms | Medium | Low | SCADA clients |
| OPC UA Client | 10-50ms | Medium | Low | Push to servers |
| MQTT | 5-30ms | High | Low | IoT/cloud |
| Sparkplug B | 5-30ms | High | Low | Ignition Edge |
| Kafka | 10-100ms | Very High | Medium | Streaming |
| AMQP | 10-50ms | High | Medium | Enterprise |
| WebSocket | 5-20ms | Medium | Low | Web browsers |
| REST API | 20-100ms | Low | Low | HTTP clients |
| MODBUS TCP | 50-200ms | Low | Low | Legacy PLCs |
βββββββββββββββββββββββββββββββ
β Your OPC UA Server β
β (All protocols enabled) β
ββββββββββββββββ¬βββββββββββββββ
β
ββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββ
β β β
βΌ βΌ βΌ
ββββββββββββ ββββββββββββ ββββββββββββ
β Ignition β β Cloud β β Legacy β
β (OPC UA β β (MQTT) β β PLC β
β Client) β β β β (MODBUS) β
ββββββββββββ ββββββββββββ ββββββββββββ
Factory Floor Edge Gateway Cloud
β β β
βββΊ PLC 1 βββ β β
βββΊ PLC 2 βββΌββΊ MODBUS βββββββ€ β
βββΊ PLC 3 βββ β β
β β
βββββββββ΄βββββββββ β
β Your Server β β
β (Multi-Proto) β β
βββββββββ¬βββββββββ β
β β
βββΊ OPC UA Client ββββββΌββΊ Cloud OPC UA
βββΊ MQTT βββββββββββββββΌββΊ AWS IoT
βββΊ Kafka ββββββββββββββΌββΊ Data Lake
β β
Local Network β
β β
Ignition Server β
(Reads via OPC UA) β
The Part Where We Pat Ourselves on the Back
π 9 Industrial Protocols:
- OPC UA Server (original) - The foundation
- OPC UA Client β NEW - The plot twist
- MQTT - The IoT darling
- Sparkplug B - Ignition's BFF
- Apache Kafka - The enterprise flex
- AMQP/RabbitMQ - The reliable one
- WebSocket - The real-time enabler
- REST API - The people's champion
- MODBUS TCP - The legacy legend
What This Thing Can Actually Do
β
Server mode (4 protocols) - Others connect to you (popular kid energy)
β
Client mode (5 protocols) - You push to others (aggressive networking)
β
Bidirectional OPC UA - Server + Client (identity crisis resolved)
β
Multi-cloud - AWS, Azure, Google (cloud-agnostic and proud)
β
Multi-SCADA - Ignition, Wonderware, etc. (doesn't play favorites)
β
Legacy support - MODBUS TCP (respecting the ancients)
β
Modern web - WebSocket + REST (keeping up with the times)
β
Enterprise - Kafka + RabbitMQ (resume fodder)
The "Why Did We Build This?" Answer Sheet
β
Ignition Edge integration (complete) - The main event
β
Historian logging (PI, Canary) - For compliance and paranoia
β
Cloud platforms (AWS, Azure) - Buzzword compliance achieved
β
Legacy PLC bridging - Bringing grandpa's hardware to the party
β
Data lake ingestion - Lake of data, ocean of possibilities
β
Real-time dashboards - Making stakeholders happy since 2025
β
IoT gateway scenarios - Edge computing with extra steps
β
Enterprise data bus - Because "integration" sounds professional
You now have a complete industrial gateway capable of bridging any protocol to any other protocol! π
Now go forth and integrate all the things. Or take a nap. Both are valid choices.
-Patrick Ryan, CTO @ Fireball Industries
"Making industrial automation slightly less painful, one protocol at a time"