A Contactless Thermometer on the MLX90614 with an OLED Display
The MLX90614 infrared sensor measures surface temperature from a distance, from a cup of tea to a forehead. We show the reading on an OLED, beep on a "fever", and look at the field of view, emissivity, and why this is not a medical device.
About the project
Every object emits infrared light, and the hotter it is, the brighter. The MLX90614 is a thermopile with a filter and a processor inside: it catches that radiation and reports a ready-made temperature over I2C. It is what infrared thermometer "guns" use. We build a pocket thermometer: digits on a 0.96″ OLED and a beep when the surface is hotter than 37.5 °C.
What you need
- ESP32 DevKit
- MLX90614 module (GY-906, the 3 V version or the 5 V one with a regulator)
- SSD1306 128×64 OLED (I2C)
- A buzzer and a 100 Ω resistor
- The Adafruit MLX90614 and Adafruit SSD1306 (+ Adafruit GFX) libraries
Wiring
Both modules share the I2C bus at different addresses (MLX90614 is 0x5A, the OLED 0x3C):
| Module | VIN/VCC | GND | SDA | SCL |
|---|---|---|---|---|
| MLX90614 | 3V3 | GND | GPIO21 | GPIO22 |
| OLED | 3V3 | GND | GPIO21 | GPIO22 |
Buzzer: GPIO25 → 100 Ω → "+", "−" → GND.
What the sensor actually measures
- Two values.
readAmbientTempC()is the temperature of the sensor's own case (≈ the air).readObjectTempC()is the average temperature of everything in its field of view. - A ~90° field of view on the GY-906 (the BAA model). At 5 cm that is a spot about 10 cm across. Step back and the sensor also "sees" the wall around the cup. For readings from afar there are narrow-field versions (BCI: 5°).
- Emissivity (ε). The sensor is set to ε = 1.0 (a perfect "black body"). Skin is ≈ 0.98, so it reads ~0.3 °C low. Polished metal with ε ≈ 0.1 is nearly "invisible": the sensor reports the room temperature reflected off it. For metal, stick on a piece of black electrical tape and measure that.
Code
// Contactless thermometer: MLX90614 + 128×64 OLED + buzzer
#include <Wire.h>
#include <Adafruit_MLX90614.h>
#include <Adafruit_SSD1306.h>
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
Adafruit_SSD1306 oled(128, 64, &Wire);
const int BUZZER = 25;
const float FEVER = 37.5; // "hot surface" threshold, °C
void setup() {
Serial.begin(115200);
if (!oled.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("OLED not found");
while (true) delay(1000);
}
oled.setTextColor(SSD1306_WHITE);
if (!mlx.begin()) {
oled.clearDisplay();
oled.println("MLX90614 missing");
oled.display();
while (true) delay(1000);
}
}
void loop() {
float obj = mlx.readObjectTempC(); // whatever the sensor looks at
float amb = mlx.readAmbientTempC(); // the sensor case ≈ the air
oled.clearDisplay();
oled.setTextSize(1);
oled.setCursor(0, 0);
oled.print("Object");
oled.setTextSize(3);
oled.setCursor(0, 16);
oled.printf("%.1f", obj);
oled.setTextSize(1);
oled.print(" C");
oled.setCursor(0, 54);
oled.printf("Ambient %.1f C", amb);
if (obj >= FEVER) {
oled.setCursor(92, 0);
oled.print("HOT!");
tone(BUZZER, 2500, 150);
}
oled.display();
Serial.printf("object %.2f °C, ambient %.2f °C\n", obj, amb);
delay(1000);
}
Why this is not a medical thermometer
- The forehead is 0.5–2 °C cooler than the body core and depends heavily on wind, sweat and hair.
- The sensor reacts to the heat of its own case: hold it by the edges, not by the cap.
- After moving it from the cold into the warm, give it 10–15 minutes for the case temperature to settle.
For comparing "hotter or colder" (pipes, sockets, motors, bearings), its ±0.5 °C accuracy is more than enough.
What next
- A "measure" button that holds the maximum over 2 seconds, like real IR guns.
- ε can be changed in software (
writeEmissivity()), but the value goes into the sensor's EEPROM and only takes effect after the sensor is power-cycled. Don't do it in everysetup(): EEPROM endurance is limited.