Skip to content

Latest commit

Β 

History

History
529 lines (444 loc) Β· 17.7 KB

File metadata and controls

529 lines (444 loc) Β· 17.7 KB

Complete Protocol Architecture

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"

System Overview (aka "What Fresh Hell Did We Build?")

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

Protocol Matrix

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"

Data Flow Examples

Example 1: Complete Multi-Protocol Setup

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

Architecture Patterns

Pattern 1: Ignition Integration

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"
    }
  }
}

Pattern 2: Historian Logging

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"
    }
  }
}

Pattern 3: Edge-to-Cloud Gateway

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
    }
  }
}

Pattern 4: Legacy PLC Integration

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
    }
  }
}

Pattern 5: Development/Testing Setup

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}
  }
}

Protocol Selection Guide

When to Use OPC UA Client

βœ… 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

When to Use MQTT

βœ… 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

When to Use Sparkplug B

βœ… 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

When to Use Kafka

βœ… 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

When to Use MODBUS TCP

βœ… 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)

When to Use REST API

βœ… 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)

Performance Comparison

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

Network Topology

Single Server Deployment

                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚   Your OPC UA Server        β”‚
                    β”‚   (All protocols enabled)   β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                   β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚                          β”‚                          β”‚
        β–Ό                          β–Ό                          β–Ό
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚ Ignition β”‚              β”‚  Cloud   β”‚              β”‚  Legacy  β”‚
  β”‚  (OPC UA β”‚              β”‚  (MQTT)  β”‚              β”‚  PLC     β”‚
  β”‚  Client) β”‚              β”‚          β”‚              β”‚ (MODBUS) β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Distributed Deployment

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)         β”‚

Summary

The Part Where We Pat Ourselves on the Back

What You Have Now

πŸŽ‰ 9 Industrial Protocols:

  1. OPC UA Server (original) - The foundation
  2. OPC UA Client ⭐ NEW - The plot twist
  3. MQTT - The IoT darling
  4. Sparkplug B - Ignition's BFF
  5. Apache Kafka - The enterprise flex
  6. AMQP/RabbitMQ - The reliable one
  7. WebSocket - The real-time enabler
  8. REST API - The people's champion
  9. MODBUS TCP - The legacy legend

Capabilities

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)

Use Cases Enabled

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"