Contents — 26 sections
Project Overview
Automatically logs a machine's uptime, speed and quality and computes OEE — turning a factory's vague sense of "how are we doing?" into the exact numbers that show where output is lost.
Every factory wants to make more with what it has, but most cannot say where their output is being lost — to stoppages, to running slow, or to scrap. OEE (Overall Equipment Effectiveness) is the standard metric that answers this, and it does so by decomposing productivity into three factors: Availability (was the machine running when it should have been?), Performance (did it run at its rated speed?), and Quality (were the parts good?). Multiply them and you get one number, 0-100%, that captures the true productive fraction of a machine — and, more usefully, three numbers that pinpoint which kind of loss is hurting you. This project measures the inputs automatically and computes OEE live, replacing gut feel and manual logs with the real figures.
The tracker senses the three inputs from the machine. Availability comes from a run/stop signal (a machine-on input, a cycle sensor, or motor current) that logs exactly when the machine was running versus down, and for how long each stoppage lasted. Performance comes from counting output (a cycle/item counter) and comparing the actual rate to the machine's ideal rate. Quality comes from a good/reject signal (a reject-station input, or manual entry) giving the good-part fraction. From these it computes each factor and the overall OEE, live, per shift and per batch — and because it logs why the machine stopped (downtime reasons) it exposes the "six big losses" that OEE is designed to attack.
The value is that OEE is actionable: a low Availability points at breakdowns and changeovers, a low Performance at minor stops and slow running, a low Quality at scrap and rework — so improvement effort goes where the loss actually is, and the same numbers verify whether a fix worked. The tracker reports to a dashboard, ranks losses, and gives operators a live OEE they can respond to. It is honest that OEE is only as good as its inputs (a correct ideal cycle time, an honest definition of planned production time, accurate good/reject counts) and that it measures effectiveness, not the whole business. But as an automatic, always-on OEE tracker, it converts a machine's activity into the industry-standard productivity numbers that show, precisely, where output is being lost and whether it is being recovered.
What this project does
- Logs machine run/stop (Availability) with per-stoppage duration and reason
- Counts output and compares to ideal rate (Performance)
- Captures good/reject counts (Quality)
- Computes Availability × Performance × Quality = OEE, live
- Reports OEE per shift/batch and ranks the losses
- Exposes the "six big losses" for targeted improvement
- Verifies whether improvements actually raised OEE
Real-World Applications
| Setting | How it is used |
|---|---|
| Machine / line productivity | Live OEE per machine to find and reduce the biggest output losses. |
| Continuous improvement / lean | Data-driven targeting of the six big losses and verification of kaizen results. |
| Shift / management reporting | Objective per-shift/batch productivity figures instead of manual logs. |
| Capacity / bottleneck analysis | Understanding true available capacity across machines. |
Deployment contexts where a build of this kind earns its keep.
Features & Capabilities
- Automatic three-factor OEE (Availability/Performance/Quality)
- Downtime logging with reasons (six big losses)
- Live and per-shift/batch OEE
- Loss ranking to target improvement
- Before/after verification of fixes
- Dashboard and operator display
- Honest about input quality and OEE's scope
Difficulty, Time & Required Skills
| Attribute | Value |
|---|---|
| Difficulty level | Intermediate |
| Estimated completion time | 12–18 hours |
| Indicative build cost | ₹2,500 – ₹4,500 |
| Primary discipline | Industrial |
| Reference platform | ESP32 DevKit V1 (ESP-WROOM-32) |
Skills you should have (or will pick up)
- Sensing run/stop, output count and good/reject
- Computing Availability, Performance, Quality and OEE
- Downtime-reason capture and loss classification
- Live/shift aggregation and dashboards
- Defining ideal cycle time and planned production time correctly
Bill of Materials
Every part below is commonly available from Indian and international hobby-electronics suppliers. Prices are indicative 2026 retail figures in Indian rupees and will drift — treat them as a budgeting guide, not a quotation.
| Component | Key specification | Qty | Approx. cost |
|---|---|---|---|
| ESP32 DevKit V1 (ESP-WROOM-32) Wi-Fi transmit bursts peak near 500 mA — size the regulator accordingly. | Dual-core Xtensa LX6 @ 240 MHz, 520 KB SRAM, 4 MB flash, Wi-Fi 802.11 b/g/n + BLE 4.2, 34 GPIO, 18× 12-bit ADC, 2× 8-bit DAC | 1 | ₹450 |
| Reed switch + magnet pair (door contact) Wire it normally-closed so a cut cable reads the same as an open door — fail-safe by construction. | NO contact, 10–15 mm operating gap, 100 V / 0.5 A, > 10⁷ operations | 1 | ₹55 |
| TCRT5000 IR reflectance sensor module Ambient sunlight saturates it — shroud the sensor on outdoor robots. | 1–8 mm optimum sensing gap, 950 nm emitter, analogue + digital out | 1 | ₹45 |
| ACS712 hall-effect current sensor (20 A) Zero-offset drifts with temperature — re-zero at boot with no load. | ±20 A, 100 mV/A, 80 kHz bandwidth, 1.2 mΩ internal resistance, 2.1 kV isolation | 1 | ₹180 |
| 0.96″ SSD1306 OLED display Static images burn in — invert or scroll the screen periodically. | 128 × 64 monochrome, 1.3–3.3 V logic, 100 kHz–400 kHz I²C | 1 | ₹250 |
| 4×4 matrix membrane keypad Debounce in software — 20 ms is enough for membrane keys. | 16 keys, 8-wire matrix, 35 × 76 mm adhesive-backed | 1 | ₹70 |
| 5 V 3 A regulated SMPS adapter Measure the real output — many "3 A" adapters sag below 4.7 V at 2 A. | 100–240 VAC in, 5 V ±5 % out, 3 A, short-circuit and over-voltage protection | 1 | ₹350 |
| Machine-state inputs Tap a clean signal for Availability | Run/stop signal (machine-on / cycle sensor / motor current) | 1 | ₹400 |
| Output counter sensor | Cycle/item sensor for Performance (count vs ideal rate) | 1 | ₹300 |
| Reject/good input + reason selector | Reject-station signal or operator buttons for Quality and downtime reasons | 1 | ₹350 |
| Andon display | Operator display/stack-light showing live OEE and state | 1 | ₹800 |
Estimated total: ₹3,250, excluding tools, shipping and consumables.
Tools and consumables
- Soldering iron (temperature controlled, 350 °C) with 0.8 mm 60/40 or lead-free solder
- Digital multimeter — continuity, DC volts and current ranges
- Wire strippers, flush cutters and a small set of precision screwdrivers
- Heat-shrink tubing and a heat gun (or a lighter, carefully)
- A laptop with a USB port and the toolchain listed above
Hardware Specifications
| Part | Specification | Supply | Interface | Reference |
|---|---|---|---|---|
| ESP32 DevKit V1 (ESP-WROOM-32) | Dual-core Xtensa LX6 @ 240 MHz, 520 KB SRAM, 4 MB flash, Wi-Fi 802.11 b/g/n + BLE 4.2, 34 GPIO, 18× 12-bit ADC, 2× 8-bit DAC | 3.3 V logic / 5 V USB | UART, SPI, I²C, I²S, CAN, PWM | Datasheet |
| Reed switch + magnet pair (door contact) | NO contact, 10–15 mm operating gap, 100 V / 0.5 A, > 10⁷ operations | passive | Digital with pull-up | Datasheet |
| TCRT5000 IR reflectance sensor module | 1–8 mm optimum sensing gap, 950 nm emitter, analogue + digital out | 3.3–5 V | Analogue + digital | Datasheet |
| ACS712 hall-effect current sensor (20 A) | ±20 A, 100 mV/A, 80 kHz bandwidth, 1.2 mΩ internal resistance, 2.1 kV isolation | 5 V | Analogue | Datasheet |
| 0.96″ SSD1306 OLED display | 128 × 64 monochrome, 1.3–3.3 V logic, 100 kHz–400 kHz I²C | 3.3–5 V | I²C (0x3C) | Datasheet |
| 4×4 matrix membrane keypad | 16 keys, 8-wire matrix, 35 × 76 mm adhesive-backed | logic level | 8 GPIO matrix scan | Datasheet |
| 5 V 3 A regulated SMPS adapter | 100–240 VAC in, 5 V ±5 % out, 3 A, short-circuit and over-voltage protection | 5 V | DC barrel / USB | Datasheet |
Consolidated electrical and interface specifications for every active part in the build.
Power Budget & Supply Sizing
Add up the typical active current of every part, then size the supply with at least 50 % headroom so transmit bursts and motor inrush never brown out the controller.
| Load | Supply rail | Typical current (mA) | Notes |
|---|---|---|---|
| ESP32 DevKit V1 (ESP-WROOM-32) | 3.3 V logic / 5 V USB | 160 | Wi-Fi transmit bursts peak near 500 mA — size the regulator accordingly. |
| TCRT5000 IR reflectance sensor module | 3.3–5 V | 20 | Ambient sunlight saturates it — shroud the sensor on outdoor robots. |
| ACS712 hall-effect current sensor (20 A) | 5 V | 10 | Zero-offset drifts with temperature — re-zero at boot with no load. |
| 0.96″ SSD1306 OLED display | 3.3–5 V | 20 | Static images burn in — invert or scroll the screen periodically. |
| 4×4 matrix membrane keypad | logic level | 1 | Debounce in software — 20 ms is enough for membrane keys. |
| 5 V 3 A regulated SMPS adapter | 5 V | 3000 | Measure the real output — many "3 A" adapters sag below 4.7 V at 2 A. |
Summed typical draw is 3211 mA. With a 1.5× design margin the supply should deliver at least 4900 mA continuously at the stated rail voltage.
Software Requirements & Development Environment
Reference toolchain: Arduino IDE 2.3.x with the ESP32 board package 3.x (or PlatformIO on VS Code). Anything newer normally works; anything older may lack the board definitions used here.
- Install the Arduino IDE 2.3.x (or PlatformIO if you prefer a real editor and dependency locking).
- Add
https://espressif.github.io/arduino-esp32/package_esp32_index.jsonunder File → Preferences → Additional Board Manager URLs, then install esp32 from the Boards Manager. - Set the correct port under Tools → Port. On Linux add yourself to the
dialoutgroup:sudo usermod -aG dialout $USERand log out and back in. - Open the Serial Monitor at 115200 baud — every sketch here logs its state there.
- Keep File → Preferences → Show verbose output during: compilation switched on while you are debugging build errors.
Required libraries
| Library | Why it is needed | Install |
|---|---|---|
| WiFi (ESP32 core) bundled | Station/AP connection management for the ESP32. | Bundled with the ESP32 Arduino core |
| PubSubClient 2.8 | Lightweight MQTT 3.1.1 client for constrained devices. | Library Manager → "PubSubClient" by Nick O'Leary |
| Adafruit SSD1306 + GFX 2.5.x | Framebuffer and text/graphics primitives for the OLED. | Library Manager → "Adafruit SSD1306" |
| NTPClient / configTime bundled | Wall-clock time from an NTP server for timestamping. | Bundled (`configTime()` on ESP32) |
| ArduinoJson 7.x | Zero-allocation JSON serialisation and parsing. | Library Manager → "ArduinoJson" by Benoit Blanchon |
| Preferences (NVS) bundled | Wear-levelled key/value storage in ESP32 flash for settings. | Bundled with the ESP32 core |
Block Diagram
The block diagram shows the functional decomposition of the system — what senses, what decides, what acts, and where the data ends up.
Circuit Diagram & Wiring
Every signal line in the build is shown below, followed by a pin-by-pin connection table you can work through with a multimeter in hand.
| Peripheral | Peripheral pin | Controller pin | Signal |
|---|---|---|---|
| Run/stop signal | in | GPIO 34 | Machine running state |
| Output sensor | PULSE | GPIO 27 | Cycle/item count |
| Reject/good | in | GPIO 26 | Quality count |
| Reason selector | keypad | GPIO matrix | Downtime reason |
| OLED/Andon | SDA/SCL | GPIO 21/22 | Live OEE + state |
| Wi-Fi | on-chip | — | Dashboard |
| RTC | SDA/SCL | GPIO 21/22 | Shift timing |
| 5V supply | +/– | 3V3 reg | Power |
Wire one row at a time and tick it off — most "it does not work" reports trace back to a single swapped pair.
Wiring explanation
- Tap a clean, unambiguous run/stop signal for Availability — a machine-on contact, a cycle sensor, or a motor-current threshold.
- Use a reliable output sensor for counting cycles/items; debounce it like a counter.
- Provide a good/reject input (reject-station signal or operator confirmation) for Quality.
- Give operators an easy way to select the downtime reason so losses are classified (the six big losses).
- Show live OEE/state on an operator display/stack-light so the floor can respond.
System Architecture
Read the stack from the bottom up: physical hardware, the firmware that drives it, the transport that moves data off the device, and the software a human actually looks at.
Working Principle
OEE is powerful because it decomposes a single fuzzy question — "how productive is this machine?" — into three precise, multiplicative factors, each capturing a distinct family of loss. Availability = running time / planned production time, hurt by breakdowns and changeovers (down time). Performance = actual output / output at ideal speed, hurt by minor stops and slow running (speed loss). Quality = good parts / total parts, hurt by scrap and rework (quality loss). Their product, OEE = A × P × Q, is the fraction of planned time that produced good product at full speed — a brutally honest number (a "typical" machine often scores far lower than its operators assume). The decomposition is the point: a single OEE tells you how much you are losing; A, P and Q together tell you which kind, which is what you can act on.
Measuring the three factors means sensing three things automatically. Availability needs a truthful run/stop signal and a truthful definition of planned production time (the time the machine was scheduled to run, excluding planned breaks) — from a machine-on input, a cycle sensor, or motor current, logging every stoppage and its duration. Performance needs the output count and the machine's ideal cycle time (the fastest it is designed to make one part): actual rate versus ideal rate gives the speed factor, and getting the ideal cycle time right is critical because it anchors the whole Performance number. Quality needs the good/reject split, from a reject-station signal or operator entry. Each is a modest sensing task, but all three are required — OEE with a factor missing or guessed is not OEE.
The classification of loss is where OEE guides action, through the six big losses it is designed to expose: breakdowns and setup/changeover (Availability); minor stops and reduced speed (Performance); startup rejects and production rejects (Quality). By capturing the reason each time the machine stops — a quick operator selection — the tracker attributes downtime to specific causes and ranks them, so improvement effort targets the biggest real loss rather than the loudest complaint. This is the crucial link from measurement to improvement: OEE does not just score you, it tells you which of the six losses to attack first, and the same live numbers then verify whether the fix actually moved the needle.
Finally, the tracker is honest about OEE's dependencies and scope. Its accuracy rests entirely on the honesty of its inputs: a wrong ideal cycle time inflates or deflates Performance, a loose definition of planned production time distorts Availability, and inaccurate good/reject counts corrupt Quality — so agreeing and getting these right is as important as the electronics. And OEE measures equipment effectiveness, not the whole business — it does not, by itself, capture demand, cost or whether you should be running the machine at all — so it is a targeting tool within a wider improvement effort, not the sole metric. Built with correct inputs and reason capture, though, an automatic OEE tracker converts a machine's raw activity into the standard, decomposable, actionable productivity numbers that show a factory exactly where its output is going and whether it is winning it back.
The maths behind it
The three factors
Availability = Run Time / Planned Production Time
Performance = (Ideal Cycle Time × Total Count) / Run Time
= Actual Rate / Ideal Rate
Quality = Good Count / Total Count
Each is a fraction 0–1 capturing one loss family.
OEE
OEE = Availability × Performance × Quality
The fraction of planned time producing GOOD parts at
FULL speed. Multiplicative → each factor gates the result.
World-class ~85%; many machines score far lower than assumed.
Six big losses (what to attack)
Availability: breakdowns, setup/changeover
Performance : minor stops, reduced speed
Quality : startup rejects, production rejects
Capture the downtime REASON to attribute and rank losses,
then fix the biggest and verify OEE improves.
Program Flowchart
The firmware is a single cooperative loop. Nothing blocks for long, so networking, sensing and the user interface all stay responsive.
Assembly Instructions
Build on a breadboard first and only commit to solder once the whole system has run for an hour without a fault.
Wire the three inputs and a reason selector
Connect a clean run/stop signal (Availability), an output counter (Performance), and a good/reject input (Quality), plus operator buttons/keypad to select downtime reasons.
Add an operator display/stack-light for live OEE and state.
Configure the anchors
Set the ideal cycle time and the planned-production-time definition (shift schedule, planned breaks) — agreed with the team, since these anchor the numbers.
Set up computation and reporting
Compute A/P/Q and OEE live, roll up per shift/batch, rank losses, and report to a dashboard.
Step-by-Step Implementation Guide
Work through these in order. Each step ends in something you can observe, so a failure is always localised to the step you just finished.
Compute the three factors and OEE
Accumulate run time, total and good counts, and stoppage reasons; compute Availability, Performance and Quality and multiply for OEE.
cppoee.inostruct OEE { uint32_t plannedS, runS; // seconds uint32_t totalCount, goodCount; float idealCycleS; // ideal seconds per part }; float availability(const OEE &o){ return o.plannedS ? (float)o.runS / o.plannedS : 0; } float performance(const OEE &o){ if (!o.runS) return 0; float ideal = o.idealCycleS * o.totalCount; // ideal run time for the count return ideal / o.runS; // capped at 1 in practice } float quality(const OEE &o){ return o.totalCount ? (float)o.goodCount / o.totalCount : 0; } float oee(const OEE &o){ return availability(o) * performance(o) * quality(o); } // Which factor is the biggest loss right now? const char* biggestLoss(const OEE &o){ float a=availability(o), p=performance(o), q=quality(o); if (a <= p && a <= q) return "Availability (downtime/changeover)"; if (p <= a && p <= q) return "Performance (slow/minor stops)"; return "Quality (scrap/rework)"; }return o.plannedS ? (float)o.runS / o.plannedS : 0Availability is run time over planned production time — the down-time factor, anchored on a correct definition of planned time.float ideal = o.idealCycleS * o.totalCountPerformance compares the ideal run time for the parts made against the actual run time, capturing speed loss — and depends on a correct ideal cycle time.return o.totalCount ? (float)o.goodCount / o.totalCount : 0Quality is the good-part fraction, the scrap/rework factor.return availability(o) * performance(o) * quality(o)OEE multiplies the three, so a weakness in any one factor gates the whole result — which is exactly why the decomposition is so informative.const char* biggestLoss(const OEE &o)Identifying which factor is lowest points improvement effort at the family of loss that is actually costing the most output.Capture reasons, rank losses, report
On each stop, capture the reason; aggregate downtime by cause into the six big losses, rank them, show live OEE on the andon, and report per shift/batch — using before/after to verify fixes.
Complete Source Code
The listing below is complete and compiles as written — there are no elided sections. Read the annotations under each block before you upload it.
/* ═══════════════════════════════════════════════════════════════
OEE Productivity Tracker — ESP32
Logs run/stop (Availability), output vs ideal (Performance), and
good/reject (Quality) to compute OEE live, captures downtime reasons
(six big losses), and reports per shift/batch to a dashboard.
OEE = Availability x Performance x Quality.
══════════════════════════════════════════════════════════════════ */
#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <Preferences.h>
#define PIN_RUN 34 // machine running (HIGH = running)
#define PIN_COUNT 27 // output pulse
#define PIN_GOOD 26 // good part (else counted as reject)
#define IDEAL_CYCLE_S 3.0f
#define SHIFT_S (8*3600)
Adafruit_SSD1306 oled(128,64,&Wire);
Preferences prefs; WiFiClient net; PubSubClient mqtt(net);
uint32_t runS=0, downS=0, total=0, good=0, shiftStart=0, lastTick=0;
bool running=false; uint32_t stopStart=0;
volatile bool countFlag=false;
void IRAM_ATTR onCount(){ countFlag=true; }
float availability(){ uint32_t planned=runS+downS; return planned? (float)runS/planned:0; }
float performance(){ return runS? (IDEAL_CYCLE_S*total)/runS : 0; }
float quality(){ return total? (float)good/total : 0; }
void setup(){
Serial.begin(115200);
pinMode(PIN_RUN,INPUT); pinMode(PIN_COUNT,INPUT_PULLUP); pinMode(PIN_GOOD,INPUT);
attachInterrupt(PIN_COUNT,onCount,FALLING);
Wire.begin(21,22); oled.begin(SSD1306_SWITCHCAPVCC,0x3C);
WiFi.begin(WIFI_SSID,WIFI_PASS); mqtt.setServer(MQTT_HOST,1883);
shiftStart=millis(); lastTick=millis();
}
void loop(){
if(!mqtt.connected()&&WiFi.status()==WL_CONNECTED) mqtt.connect("oee-1");
mqtt.loop();
uint32_t now=millis();
uint32_t dt=(now-lastTick)/1000; if(dt){ lastTick+=dt*1000; }
bool isRunning = digitalRead(PIN_RUN)==HIGH;
if (isRunning) runS+=dt; else downS+=dt;
// state transition -> capture stop / reason
if (running && !isRunning){ stopStart=now; } // just stopped
if (!running && isRunning && stopStart){ // just restarted
uint32_t dur=(now-stopStart)/1000;
const char* reason = getSelectedReason(); // operator selection
logDowntime(dur, reason); // attribute the loss
stopStart=0;
}
running=isRunning;
if (countFlag){ // an output part
countFlag=false; total++;
if (digitalRead(PIN_GOOD)==HIGH) good++; // else it's a reject
}
float a=availability(), p=performance(), q=quality();
float oee=a*p*q;
oled.clearDisplay(); oled.setCursor(0,0);
oled.printf("OEE %.0f%%\nA %.0f P %.0f Q %.0f\n%s",
oee*100, a*100, p*100, q*100, isRunning?"RUN":"DOWN");
oled.display();
char m[220];
snprintf(m,sizeof m,
"{\"oee\":%.3f,\"a\":%.3f,\"p\":%.3f,\"q\":%.3f,"
"\"total\":%u,\"good\":%u,\"run\":%s}",
oee,a,p,q,total,good, isRunning?"true":"false");
mqtt.publish("oee/machine1/live", m);
// shift rollup
if (now-shiftStart >= SHIFT_S*1000UL){
mqtt.publish("oee/machine1/shift", m);
runS=downS=total=good=0; shiftStart=now; // reset for next shift
}
delay(1000);
}
Configuration & Calibration
Configuration steps
- Set the ideal cycle time and the planned-production-time/shift definition (agreed with the team).
- Configure the run/stop, output and good/reject inputs and the downtime-reason list (six big losses).
- Set shift/batch boundaries and the andon/dashboard reporting.
- Decide how good/reject is determined (reject station vs operator entry).
Calibration procedure
An uncalibrated sensor produces confident, precise, wrong numbers. Do this once per physical unit and record the constants.
Ideal cycle time
Confirm the machine's true ideal cycle time (fastest sustainable per-part time); it anchors Performance.
Planned time
Agree what counts as planned production time (schedule minus planned breaks) so Availability is meaningful.
Counts
Verify output and good/reject counts against a manual check so Performance and Quality are accurate.
Network Architecture & Connectivity
Communication protocol
Live OEE and A/P/Q publish continuously; shift/batch rollups and downtime-with-reason publish at boundaries and on events, feeding loss ranking.
| Topic / endpoint | Direction | Payload |
|---|---|---|
oee/machine1/live | node → dashboard | OEE, A, P, Q, counts, run state |
oee/machine1/downtime | node → dashboard | stoppage duration + reason |
oee/machine1/shift | node → MES | per-shift/batch OEE rollup |
Message contract between the device and the broker.
Cloud platform configuration
A dashboard/MES trends OEE and its factors per machine/shift/batch, ranks the six big losses, and supports before/after verification of improvements.
Dashboard setup
Live OEE and A/P/Q per machine, a Pareto of downtime reasons, shift/batch trends, and improvement comparisons.
Mobile app integration
Alerts on prolonged downtime or a significant OEE drop; shift summaries.
Security considerations
- Authenticate nodes so productivity data is trustworthy.
- Agree input definitions (ideal cycle time, planned time) so numbers are comparable.
- Alert on tracker silence so a machine goes not-unmonitored.
Testing Procedure & Expected Output
Test from the bottom up. Confirm power, then each sensor in isolation, then the integrated loop — the first failing step tells you exactly where to look.
| Test | What you should see |
|---|---|
| Run at ideal speed, all good | A, P, Q and OEE near 100% |
| Introduce a stoppage | Availability drops; downtime logged with reason |
| Run slow / minor stops | Performance drops |
| Produce rejects | Quality drops |
| End a shift | Per-shift OEE rolled up and reset |
| Apply a fix and compare | OEE change verifies whether the fix worked |
Bench-test checklist. If a row fails, stop and fix it before moving on.
Expected output
The andon shows live OEE and A/P/Q; the dashboard trends OEE per shift/batch, ranks downtime reasons (six big losses), and compares before/after.
{
"oee": 0.62,
"a": 0.82,
"p": 0.86,
"q": 0.88,
"total": 1240,
"good": 1091,
"run": true
}
An OEE of 62% with A/P/Q of 82/86/88 shows Availability is the biggest loss here — so the ranked downtime reasons point straight at the breakdowns/changeovers to attack first.
Troubleshooting: Common Errors & Fixes
Performance Optimisation
- Accumulate time and counts at 1 Hz; OEE does not need high-rate sampling.
- Debounce the output counter and use interrupts for accurate counts.
- Roll up per shift/batch and report live plus on events.
- Keep reason capture one-touch so it actually happens.
- Replace every
delay()with amillis()comparison — blocking delays are the single most common cause of dropped readings. - Sample sensors on a fixed cadence and publish on a slower one; you almost never need to transmit at the sampling rate.
- Move networking into its own FreeRTOS task so a slow DNS lookup cannot stall the control loop.
- Use
uint8_t/uint16_twhere the range allows; on an 8-bit AVR a 32-bit add costs four times as much. - Batch several samples into one MQTT publish. Radio time, not CPU time, dominates the energy budget.
- Set the MQTT keep-alive to a value that matches your reporting interval so the broker does not churn reconnections.
- For battery builds use deep sleep between samples: an ESP32 drops from ~160 mA awake to about 10 µA asleep, which is the difference between days and months of runtime.
Safety Precautions
- Sense machine signals safely and without interfering with machine control.
- OEE is only as good as its inputs — agree the ideal cycle time and planned-time definition, and keep counts accurate.
- Use OEE to target losses, not to blame operators; capture reasons constructively.
- OEE measures effectiveness, not the whole business — keep it in context.
- Wear eye protection when soldering or cutting, and solder in a ventilated space — rosin flux fumes are a respiratory irritant.
- Power the circuit through a bench supply with a current limit while you are testing. A 300 mA limit turns a wiring mistake into a beep instead of a dead board.
- Disconnect power before changing any wiring. Hot-plugging a sensor onto a live bus is the fastest way to lose a controller.
Maintenance
- Re-verify ideal cycle time and planned-time definitions after process changes.
- Check count/quality inputs against manual counts periodically.
- Keep the downtime-reason list meaningful and current.
- Review loss rankings and confirm improvements with before/after OEE.
- Re-check every screw terminal and header after the first week — thermal cycling loosens connections that felt tight on day one.
- Keep the broker and dashboard containers patched, and rotate device credentials at least once a year.
- Recalibrate at the interval given in the calibration section, and keep the constants in a text file next to the firmware — not only in flash.
- Keep a short logbook of firmware versions and what changed. Six months later you will not remember why that constant is 1.083.
Future Improvements & Upgrades
A working v1 is a platform, not a finish line. These are the upgrades that add the most capability for the least rework.
- Auto-classify downtime causes from signals to reduce manual reason entry.
- Integrate with MES/ERP for scheduling-aware OEE and TEEP.
- Add micro-stop detection for finer Performance analysis.
- Benchmark OEE across machines/lines and shifts.
- Design a proper PCB. Once the breadboard version has run for a month, moving to a two-layer board removes the intermittent-contact failures that dominate prototype faults.
- Add over-the-air firmware updates so you never have to physically reach a deployed node again.
- Add persistent local storage (microSD or the on-chip flash) so a network outage does not create a hole in your data.
- Move configuration out of the source: a captive-portal setup page or a JSON config file makes the build reusable without a recompile.
- Add a battery and solar option so the unit survives a power cut and can be sited away from a socket.
- Write a small test harness that feeds synthetic sensor values through the decision logic, so you can validate thresholds without physically triggering the event.
Frequently Asked Questions
References & Learning Resources
These are the primary sources worth reading in full. Manufacturer datasheets always outrank forum posts when the two disagree.
- Overall Equipment Effectiveness (OEE)Reference
- The six big lossesReference
- Total Productive Maintenance (TPM)Reference
- Lean manufacturing and continuous improvementReference
- Andon (visual management)Reference