Industrial IoT Automation with n8n: No-Code Workflow Integration

Amazeng Technical Team
10 min read
n8nWorkflow AutomationMQTTIndustrial IoTNo-CodeIntegrationERP

Introduction

In industrial facilities, managing data from dozens of sensors can become complex. Alerting, reporting, ERP system integration – all require separate development effort. n8n, an open-source workflow automation platform, simplifies these processes with a visual no-code interface.

In this article, we examine how to automate data flows from our ZMA Data Acquisition and GDT Digital Transmitter devices using n8n, without writing code.

What is n8n?

n8n (nodemation) is an automation platform that connects applications and services. The open-source alternative to Zapier/Make.

Key Features

Open Source: Self-hosted, full control
Visual Interface: Workflow design with drag & drop
300+ Integrations: MQTT, HTTP, Email, Slack, SAP, databases
Code Support: JavaScript when needed
Low Latency: Real-time triggers

n8n vs Alternatives

Featuren8nZapierMake (Integromat)
Open Source✅ Yes❌ No❌ No
Self-Hosted✅ Yes❌ No❌ No
MQTT Support✅ Native❌ No⚠️ Limited
Unlimited Workflows✅ Yes❌ Paid plans❌ Paid plans
Cost (1000 ops/month)Free$19.99$9.00

System Architecture

┌───────────────────────────────────────────────────┐
│                Factory Network                    │
│                                                   │
│  ┌─────────┐      MQTT       ┌──────────────┐   │
│  │ ZMA/GDT │─────────────────►│              │   │
│  │ Devices │                  │  MQTT Broker │   │
│  └─────────┘                  │  (Mosquitto) │   │
│                               └──────┬───────┘   │
│                                      │            │
│                               ┌──────▼───────┐   │
│                               │     n8n      │   │
│                               │  Automation  │   │
│                               │   Server     │   │
│                               └──┬─────┬─────┘   │
└──────────────────────────────────┼─────┼─────────┘
                                   │     │
                    ┌──────────────┘     └─────────────┐
                    │                                  │
            ┌───────▼────────┐              ┌──────────▼────────┐
            │  Email / Slack │              │   ERP / Database  │
            │  Notifications │              │   (SAP, REST API) │
            └────────────────┘              └───────────────────┘

n8n Installation (Docker)

docker-compose.yml

version: '3.8'

services:
  n8n:
    image: n8nio/n8n:latest
    container_name: n8n
    restart: always
    ports:
      - '5678:5678'
    environment:
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=admin
      - N8N_BASIC_AUTH_PASSWORD=secure_password_123
      - N8N_HOST=n8n.factory.local
      - WEBHOOK_URL=http://n8n.factory.local:5678
      - N8N_PROTOCOL=http
      - NODE_ENV=production
    volumes:
      - n8n_data:/home/node/.n8n
      - /var/run/docker.sock:/var/run/docker.sock

volumes:
  n8n_data:

Start Services

docker-compose up -d

# Access web interface
# http://localhost:5678

Workflow 1: Tank Weight Alert System

Scenario

Send email and Slack notification when milk tank weight exceeds 90% capacity.

n8n Workflow Configuration

Nodes:

  1. MQTT Trigger → Listen to topic factory/tank/+/weight
  2. Function → Calculate fill percentage
  3. IF → Check if >90%
  4. Email → Send warning email
  5. Slack → Post to #production channel

Visual Workflow:

┌──────────────┐
│ MQTT Trigger │
│ Topic:       │
│ factory/tank │
│    /+/weight │
└──────┬───────┘
       │
       ▼
┌──────────────┐
│   Function   │
│ Calculate %  │
└──────┬───────┘
       │
       ▼
┌──────────────┐
│      IF      │
│ weight > 90% │
└──┬───────┬───┘
   │       │
   │ YES   │ NO
   │       └──► (End)
   ▼
┌──────────────┐
│    Email     │
│   To: ops@   │
└──────┬───────┘
       │
       ▼
┌──────────────┐
│    Slack     │
│ #production  │
└──────────────┘

MQTT Trigger Node Configuration

{
  "protocol": "mqtt",
  "host": "192.168.1.10",
  "port": 1883,
  "topics": "factory/tank/+/weight",
  "qos": 1,
  "credentials": {
    "username": "mqtt_user",
    "password": "mqtt_password"
  }
}

Function Node (Calculate Fill %)

// Received MQTT message structure:
// { "tank_id": 1, "weight": 4520.5, "capacity": 5000 }

const tankData = items[0].json

const fillPercent = (tankData.weight / tankData.capacity) * 100

return {
  json: {
    ...tankData,
    fill_percent: fillPercent,
    alert_level: fillPercent > 90 ? 'HIGH' : 'NORMAL',
  },
}

Email Node Configuration

{
  "fromEmail": "[email protected]",
  "toEmail": "[email protected]",
  "subject": "⚠️ Tank {{$json.tank_id}} Capacity Alert",
  "text": "Tank {{$json.tank_id}} is {{$json.fill_percent}}% full ({{$json.weight}} kg / {{$json.capacity}} kg).\n\nAction required: Prepare for milk collection.",
  "html": "<h2>Tank Capacity Alert</h2><p>Tank <strong>{{$json.tank_id}}</strong></p><p>Fill Level: <strong style='color:red'>{{$json.fill_percent}}%</strong></p>"
}

Workflow 2: Daily Production Report

Scenario

Generate Excel report with yesterday's all tank data and email every morning at 08:00.

Workflow

┌──────────────┐
│   Schedule   │
│ Cron: 0 8 ** │
└──────┬───────┘
       │
       ▼
┌──────────────┐
│   HTTP Req   │
│ GET /api/    │
│ tank_data    │
└──────┬───────┘
       │
       ▼
┌──────────────┐
│ Function     │
│ Format data  │
└──────┬───────┘
       │
       ▼
┌──────────────┐
│ Spreadsheet  │
│ Create Excel │
└──────┬───────┘
       │
       ▼
┌──────────────┐
│    Email     │
│ + Attachment │
└──────────────┘

HTTP Request Node (Get Data)

{
  "method": "GET",
  "url": "http://api.factory.local/v1/tank_data",
  "qs": {
    "date": "{{$now.minus({days: 1}).toFormat('yyyy-MM-dd')}}",
    "format": "json"
  },
  "authentication": "headerAuth",
  "headers": {
    "Authorization": "Bearer {{$credentials.apiToken}}"
  }
}

Function Node (Format for Excel)

// Transform API response to Excel-friendly format
const rawData = items[0].json.data

const formattedData = rawData.map(record => ({
  'Tank ID': record.tank_id,
  Timestamp: record.timestamp,
  'Weight (kg)': record.weight,
  'Fill %': Math.round(record.fill_percent),
  Status: record.status,
}))

return formattedData.map(row => ({ json: row }))

Spreadsheet Node Configuration

{
  "operation": "toFile",
  "fileFormat": "xlsx",
  "fileName": "Daily_Production_Report_{{$now.toFormat('yyyy-MM-dd')}}.xlsx",
  "sheetName": "Tank Data",
  "headerRow": true
}

Workflow 3: ERP System Integration

Scenario

When GDT weighing is complete, automatically create production record in SAP ERP system.

Workflow

┌──────────────┐
│    Webhook   │
│ /weighing-   │
│  complete    │
└──────┬───────┘
       │
       ▼
┌──────────────┐
│   Function   │
│ Map to SAP   │
│   format     │
└──────┬───────┘
       │
       ▼
┌──────────────┐
│  HTTP Req    │
│ POST SAP API │
│ /production  │
└──────┬───────┘
       │
       ▼
┌──────────────┐
│      IF      │
│   Success?   │
└──┬───────┬───┘
   │       │
  YES      NO
   │       │
   ▼       ▼
┌─────┐ ┌─────┐
│ OK  │ │Error│
│ Log │ │Retry│
└─────┘ └─────┘

Webhook Trigger

{
  "path": "weighing-complete",
  "httpMethod": "POST",
  "responseMode": "lastNode",
  "authentication": "headerAuth"
}

Example webhook call from HMI:

curl -X POST http://n8n.factory.local:5678/webhook/weighing-complete \
  -H "Authorization: Bearer abc123xyz" \
  -H "Content-Type: application/json" \
  -d '{
    "batch_id": "MILK-2025-001",
    "tank_id": 1,
    "gross_weight": 4850.5,
    "tare_weight": 350.0,
    "net_weight": 4500.5,
    "timestamp": "2025-12-29T14:30:00Z"
  }'

Function Node (SAP Format Mapping)

// Map weighing data to SAP production order format
const data = items[0].json

return {
  json: {
    ProductionOrder: {
      OrderNumber: data.batch_id,
      Material: 'MILK-RAW',
      Quantity: data.net_weight,
      QuantityUnit: 'KG',
      Plant: '1000',
      WorkCenter: 'WEIGHING-01',
      StartDate: data.timestamp,
      EndDate: data.timestamp,
      Status: 'COMPLETED',
    },
  },
}

HTTP Request to SAP

{
  "method": "POST",
  "url": "https://sap.factory.com/sap/opu/odata/sap/API_PRODUCTION_ORDER_2_SRV/A_ProductionOrder",
  "authentication": "oAuth2",
  "bodyContentType": "json",
  "body": "={{$json.ProductionOrder}}"
}

Error Handling and Retry Logic

Retry on Failure

// Error Handler Node
const MAX_RETRIES = 3
const currentRetry = $executionId.split('-').length - 1

if (currentRetry < MAX_RETRIES) {
  // Exponential backoff
  const waitTime = Math.pow(2, currentRetry) * 1000 // 1s, 2s, 4s

  return {
    json: {
      retry: true,
      wait_ms: waitTime,
      attempt: currentRetry + 1,
    },
  }
} else {
  // Max retries exceeded, send alert
  return {
    json: {
      retry: false,
      error: 'Max retries exceeded',
      notify_admin: true,
    },
  }
}

Performance and Scalability

n8n Resource Usage

MetricValue
CPU0.5-1 core (idle)
RAM512 MB (idle), 2 GB (active)
Storage~100 MB + workflow data
Throughput~100 workflows/second

Scaling for Large Facilities

For 100+ sensors:

  1. Queue-based processing (MQTT → Redis Queue → n8n)
  2. Multiple n8n instances (Docker Swarm/Kubernetes)
  3. Database for workflow results (PostgreSQL)

Conclusion

n8n enables rapid automation of complex data flows in industrial facilities without code. Especially powerful for:

MQTT to Email/Slack alerts
Automated reporting (Excel, PDF)
ERP system integration (SAP, Odoo)
Multi-system workflows

Our ZMA and GDT devices can be easily integrated with n8n via Modbus → MQTT gateway for complete workflow automation.