Smart Manufacturing

Motor Current Monitoring with CT Clamps and MQTT for Early Fault Detection

Clip a CT clamp around a motor lead, measure RMS current with an ESP32, publish it over MQTT and use a small Python service to detect overloads, frequent starts and drift away from normal load.

Motor current monitoring setup with a CT clamp on an electric motor cable sending RMS current readings to an MQTT dashboard
Run this on your own MQTT brokerGet a private, managed MQTT broker on the Free plan and start from ready-made code samples.
Try it free Code samples No card required

Motor current monitoring turns the power cable of any electric motor into a health sensor, without touching the machine itself. In this tutorial you will clip a non-invasive CT clamp onto a motor lead, measure RMS current with an ESP32, publish it over MQTT and run a Python service that flags overloads, excessive starts and abnormal load patterns.

Why Motor Current Is Such a Useful Signal

Current tells you how hard a motor is working. Because the clamp sits around the cable in the electrical cabinet, you can retrofit it on old machines that have no data interface at all, and you never need to mount anything on rotating parts.

From a single current reading per second you can derive a surprising amount:

  • Running state: off, idle (motor turning with no load) or loaded. This is often the cheapest way to feed machine downtime tracking.
  • Overload: current above the nameplate full-load amps for longer than a short start-up period.
  • Load drift: a conveyor drawing gradually more current may have a dragging bearing, a misaligned belt or product build-up. A pump drawing less may be running dry or cavitating.
  • Start frequency: too many starts per hour overheat windings, and a sudden rise often reveals a control problem.
  • Phase imbalance: with one clamp per phase, unequal currents point to supply problems or winding faults.

More advanced techniques such as motor current signature analysis look at the frequency spectrum of the current to detect broken rotor bars and bearing defects. They need much faster sampling and dedicated hardware. Everything in this article works with a few RMS values per second and still catches the most common operational problems.

Safety First

A CT clamp is non-invasive: it wraps around a single insulated conductor and never makes electrical contact. Even so, the clamp is installed inside a cabinet with live parts. Have a qualified electrician install it with the cabinet isolated, clamp around one phase conductor only (never the whole multi-core cable, where the fields cancel), and keep the low-voltage sensor wiring separated from power wiring.

Hardware

Part Purpose Notes
ESP32 DevKit Sampling, RMS calculation, Wi-Fi and MQTT Any ESP32 with an ADC1 pin
SCT-013-030 CT clamp Measures current up to 30 A Voltage-output version, 1 V at rated current
2 x 10 kOhm resistors Bias the signal to mid-supply Forms a voltage divider from 3.3 V
10 uF capacitor Stabilises the bias point Between the divider midpoint and GND
3.5 mm jack socket Connects the clamp Optional, but tidier than cutting the plug

Pick a clamp rated just above the motor's full-load current for the best resolution. A 30 A clamp on a 3 A motor will work, but the signal will be small and noisy.

Wiring

The clamp outputs an AC voltage centred on zero, while the ESP32 ADC only reads positive voltages. Bias it to the middle of the range:

  1. Connect the two 10 kOhm resistors in series between 3.3 V and GND.
  2. Connect the 10 uF capacitor from the midpoint to GND.
  3. Connect one clamp lead to the midpoint and the other to GPIO 34.

GPIO 34 belongs to ADC1, which keeps working while Wi-Fi is active. The ESP32 SCT-013 current sensor guide covers calibration and wiring variants in more detail.

Firmware: Motor Current Monitoring on the ESP32

The sketch samples the ADC 2,000 times over 200 ms, which covers ten mains cycles at 50 Hz and twelve at 60 Hz. It removes the DC bias by subtracting the mean, computes the RMS voltage and converts it to amps. Every second it publishes the current and a simple state.

#include <WiFi.h>
#include <PubSubClient.h>
#include <math.h>

const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";
const char* MQTT_HOST = "broker.connectmq.com";
const char* CLIENT_ID = "motor-ct-9be2c4";
const char* TOPIC = "connectmq/demo/9be2c4/line1/conveyor1/current";

const int CT_PIN = 34;
const float AMPS_PER_VOLT = 30.0f;  // SCT-013-030: 1 V RMS = 30 A
const float CAL = 1.00f;            // adjust after comparing with a clamp meter
const int SAMPLES = 2000;
const uint32_t SAMPLE_US = 100;     // 10 kHz, 200 ms window

const float IDLE_A = 0.5f;          // below this the motor is off
const float LOADED_A = 2.0f;        // above this the motor is under load

WiFiClient net;
PubSubClient mqtt(net);
uint16_t samples[SAMPLES];

float measureAmps() {
  uint32_t next = micros();
  for (int i = 0; i < SAMPLES; i++) {
    while ((int32_t)(micros() - next) < 0) { }
    next += SAMPLE_US;
    samples[i] = analogReadMilliVolts(CT_PIN);
  }
  double mean = 0;
  for (int i = 0; i < SAMPLES; i++) mean += samples[i];
  mean /= SAMPLES;
  double sumSq = 0;
  for (int i = 0; i < SAMPLES; i++) {
    double d = samples[i] - mean;
    sumSq += d * d;
  }
  double vrms = sqrt(sumSq / SAMPLES) / 1000.0;
  return vrms * AMPS_PER_VOLT * CAL;
}

void ensureConnected() {
  if (WiFi.status() != WL_CONNECTED) {
    WiFi.begin(WIFI_SSID, WIFI_PASS);
    while (WiFi.status() != WL_CONNECTED) delay(250);
  }
  while (!mqtt.connected()) {
    if (!mqtt.connect(CLIENT_ID)) delay(2000);
  }
}

void setup() {
  Serial.begin(115200);
  analogSetPinAttenuation(CT_PIN, ADC_11db);
  WiFi.mode(WIFI_STA);
  mqtt.setServer(MQTT_HOST, 1883);
  ensureConnected();
}

void loop() {
  ensureConnected();
  mqtt.loop();

  static uint32_t lastPub = 0;
  if (millis() - lastPub < 1000) return;
  lastPub = millis();

  float amps = measureAmps();
  if (amps < 0.1f) amps = 0;  // suppress noise floor
  const char* state = amps < IDLE_A ? "off" : amps < LOADED_A ? "idle" : "loaded";

  char payload[128];
  snprintf(payload, sizeof(payload),
           "{\"current_a\":%.2f,\"state\":\"%s\",\"uptime_s\":%lu}",
           amps, state, millis() / 1000);
  mqtt.publish(TOPIC, payload);
  Serial.println(payload);
}

Calibrate once with a trusted clamp meter: run the motor at steady load, compare both readings and set CAL to the ratio. Then set IDLE_A and LOADED_A by observing the real machine running empty and loaded.

Check the stream from any terminal:

mosquitto_sub -h broker.connectmq.com -p 1883 -i ct-viewer-9be2c4 -t "connectmq/demo/9be2c4/#" -v

Detecting Overloads and Abnormal Patterns

The device reports raw facts. Interpretation belongs in a service that can see history. The Python subscriber below (paho-mqtt 2.x) implements four checks that cover most practical needs:

  1. Overload: current above the nameplate rating for more than a grace period, which ignores normal inrush at start-up.
  2. Start counting: transitions from off to running, counted over a sliding hour.
  3. Load drift: the loaded-state average over the last ten minutes compared with a learned normal.
  4. Stale data: no message for 30 seconds means the sensor or network is down.
import json
import time
from collections import deque
import paho.mqtt.client as mqtt

PREFIX = "connectmq/demo/9be2c4"
RATED_A = 8.5               # motor nameplate full-load amps
OVERLOAD_GRACE_S = 10
MAX_STARTS_PER_HOUR = 6
DRIFT_LIMIT = 0.20          # 20 % away from learned normal
LEARN_SAMPLES = 1800        # 30 minutes of loaded running

over_since = None
last_state = "off"
starts = deque()
loaded = deque(maxlen=600)  # last 10 minutes of loaded samples
learn = []
normal = None
last_seen = time.time()

def alert(client, kind, detail):
    msg = {"ts": int(time.time()), "kind": kind, **detail}
    client.publish(f"{PREFIX}/line1/conveyor1/alert", json.dumps(msg), qos=1)
    print("ALERT", msg)

def on_connect(client, userdata, flags, reason_code, properties):
    client.subscribe(f"{PREFIX}/line1/conveyor1/current", qos=1)

def on_message(client, userdata, msg):
    global over_since, last_state, normal, last_seen
    d = json.loads(msg.payload)
    amps, state, now = d["current_a"], d["state"], time.time()
    last_seen = now

    if amps > RATED_A:
        over_since = over_since or now
        if now - over_since >= OVERLOAD_GRACE_S:
            alert(client, "overload", {"current_a": amps, "rated_a": RATED_A})
            over_since = now  # re-alert at most once per grace period
    else:
        over_since = None

    if last_state == "off" and state != "off":
        starts.append(now)
    while starts and now - starts[0] > 3600:
        starts.popleft()
    if len(starts) > MAX_STARTS_PER_HOUR:
        alert(client, "frequent_starts", {"starts_last_hour": len(starts)})
        starts.clear()
    last_state = state

    if state == "loaded":
        if normal is None:
            learn.append(amps)
            if len(learn) >= LEARN_SAMPLES:
                normal = sorted(learn)[len(learn) // 2]
                print(f"learned normal loaded current: {normal:.2f} A")
        else:
            loaded.append(amps)
            if len(loaded) == loaded.maxlen:
                avg = sum(loaded) / len(loaded)
                if abs(avg - normal) / normal > DRIFT_LIMIT:
                    alert(client, "load_drift", {"avg_a": round(avg, 2), "normal_a": round(normal, 2)})
                    loaded.clear()

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="motor-analytics-9be2c4")
client.on_connect = on_connect
client.on_message = on_message
client.connect("broker.connectmq.com", 1883, keepalive=60)
client.loop_start()
while True:
    time.sleep(5)
    if time.time() - last_seen > 30:
        alert(client, "stale", {"seconds_silent": int(time.time() - last_seen)})
        last_seen = time.time()

For the overload rule alone, you do not even need this service. A threshold alert rule in the ConnectMQ portal on the current_a field will log every crossing in the alerts log. Keep the Python service for the stateful checks such as drift and start counting.

Interpreting What You See

Pattern Likely causes Typical action
Current slowly rising under the same load Bearing drag, misalignment, belt tension, product build-up Inspect mechanics, confirm with vibration
Current dropping on a pump Dry running, closed valve, worn impeller, cavitation Check process conditions and suction side
Frequent short overloads Jams, undersized motor, process changes Review process and motor sizing
Many starts per hour Control loop hunting, sensor chatter Tune hysteresis in the control logic
Unequal phase currents Supply imbalance, loose connection, winding fault Electrical inspection

Current is strongest when combined with other signals. A rising current with rising vibration points to mechanics, while rising current with normal vibration and rising bearing temperature monitoring readings narrows the search further. The predictive maintenance with IoT article shows how these signals combine into a maintenance strategy.

Choosing Sensible Thresholds

Start from the motor nameplate, not from guesses. The full-load amps value is the upper bound for continuous operation, so the overload rule should use it directly, with a grace period long enough to cover the normal start-up inrush you observe on that machine. Direct-on-line starts draw a large inrush for a second or two, while soft starters and drives ramp up gradually, so the right grace period differs per motor.

For drift, learn the normal loaded current from a period when the machine is known to be healthy and the product mix is typical. If the line runs several products with very different loads, learn one normal value per product or recipe and include the active recipe in the payload. Otherwise every product change will look like an anomaly and operators will learn to ignore the alerts, which defeats the purpose of monitoring.

Going to Production

The public broker is great for testing, but its topics are visible to everyone. For real motors:

  • Create a private broker in the ConnectMQ portal and use the generated username, password and client ID.
  • Switch to TLS on port 8883 with WiFiClientSecure.
  • Use ISA-95 topics such as acme/plant1/packaging/line1/conveyor1/current so assets group naturally in the devices view.
  • Add a Last Will message so a dead sensor is reported as offline immediately.

A hosted MQTT broker keeps that infrastructure patched and available while you focus on the analytics. To see how current monitoring fits a full plant data architecture, read the smart manufacturing guide.

Monitor Your Motors with ConnectMQ

ConnectMQ runs your MQTT broker in the cloud with TLS, MQTT 5, a live topic explorer and threshold alerts built into the portal. Sign up at app.connectmq.com on the free Serverless plan, no credit card required, and connect your first CT clamp today.

Frequently Asked Questions

What can motor current monitoring detect?

It reliably detects running state, overloads, abnormal start frequency, load drift and phase imbalance. Detecting rotor bar or bearing defects from current requires high-speed sampling and spectral analysis.

Is a CT clamp safe to install on a running motor?

The clamp is non-invasive, but it is installed in a cabinet with live parts. A qualified electrician should install it with the cabinet isolated.

How often should I publish motor current readings?

Once per second is a good default for state and overload detection. Slower rates such as every 10 seconds work for pure trend monitoring.

Why does my reading show current when the motor is off?

That is the ADC noise floor. Suppress values below a small threshold in firmware and keep sensor wiring away from power cables.

Related articles

OEE vs TEEP vs OOE: Which Metric Should You Use?

OEE, OOE and TEEP share the same performance and quality factors but measure against different time bases. This comparison works through one example and lists the MQTT signals each metric needs.

7 min read

All articles →

Your private MQTT broker is a few clicks away

Create an account, get your broker credentials and connect your first device — no servers to install, patch or scale.