#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>
#include <math.h>
// -------------------- OLED --------------------
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Common I2C addresses: 0x3C or 0x3D ???
#define OLED_ADDR 0x3C
// -------------------- DHT22 --------------------
#define DHTPIN 16
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
// -------------------- NTC ADC pins (ADC1) --------------------
#define NTC1_PIN 34
#define NTC2_PIN 35
// -------------------- NTC / divider constants --------------------
// If you don't know your exact thermistor spec, these are common defaults for "10k NTC 3950"
const float R_FIXED = 10000.0; // fixed resistor value in ohms (10k)
const float R0 = 10000.0; // thermistor resistance at T0_K (10k at 25C)
const float T0_K = 25.0 + 273.15; // 25C in Kelvin
const float BETA = 3950.0; // beta value
// -------------------- ADC settings --------------------
const int ADC_MAX = 4095; // 12-bit ADC on ESP32
const float VCC = 3.3; // reference / supply
int readAdcAvg(int pin, int samples = 10) {
long sum = 0;
for (int i = 0; i < samples; i++) {
sum += analogRead(pin);
delay(2);
}
return (int)(sum / samples);
}
float readNTC_C(int pin) {
int raw = readAdcAvg(pin, 12);
raw = constrain(raw, 1, ADC_MAX - 1);
float v = (raw * VCC) / ADC_MAX;
// Guard against divide-by-near-zero (wiring fault / saturation)
if (v <= 0.001) return NAN;
if (v >= (VCC - 0.001)) return NAN;
float r_ntc = (R_FIXED * v) / (VCC - v);
float invT = (1.0 / T0_K) + (1.0 / BETA) * log(r_ntc / R0);
float tempK = 1.0 / invT;
return tempK - 273.15;
}
void oledPrintLine(int y, const String &s) {
display.setCursor(0, y);
display.print(s);
}
void setup() {
Serial.begin(115200);
// I2C on requested pins
Wire.begin(21, 22);
// OLED init
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
Serial.println("OLED init failed (check address 0x3C/0x3D and wiring).");
while (true) delay(100);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
// DHT init
dht.begin();
// ADC setup
analogReadResolution(12); // 0..4095
analogSetAttenuation(ADC_11db); // good range up to ~3.3V (practical)
display.clearDisplay();
oledPrintLine(0, "ESP32 Temp Monitor");
oledPrintLine(16, "Starting sensors...");
display.display();
delay(1500);
}
void loop() {
// --- Read DHT22 ---
float dhtT = dht.readTemperature(); // C
float dhtH = dht.readHumidity();
// --- Read NTCs ---
float ntc1C = readNTC_C(NTC1_PIN);
float ntc2C = readNTC_C(NTC2_PIN);
oledPrintLine(30, isnan(ntc1C) ? "NTC1 : read fail" : "NTC1 : " + String(ntc1C, 1) + "C");
oledPrintLine(44, isnan(ntc2C) ? "NTC2 : read fail" : "NTC2 : " + String(ntc2C, 1) + "C");
// Handle DHT read failures (common if wiring/pullup is off)
bool dhtOk = !(isnan(dhtT) || isnan(dhtH));
// --- OLED ---
display.clearDisplay();
oledPrintLine(0, "Temps (C)");
display.drawLine(0, 10, 127, 10, SSD1306_WHITE);
if (dhtOk) {
oledPrintLine(14, "DHT22: " + String(dhtT, 1) + "C " + String(dhtH, 0) + "%");
} else {
oledPrintLine(14, "DHT22: read fail");
}
//oledPrintLine(30, "NTC1 : " + String(ntc1C, 1) + "C");
//oledPrintLine(44, "NTC2 : " + String(ntc2C, 1) + "C");
// Bottom row Y position
int y = 54; // Adjust if your font is taller
// Left temperature
oledPrintXY(0, y, "NTC1: " + String(ntc1C, 1) + "C");
// Right temperature (roughly half the screen)
oledPrintXY(64, y, "NTC2: " + String(ntc2C, 1) + "C");
display.display();
// --- Serial debug ---
Serial.print("DHT22: ");
if (dhtOk) {
Serial.print(dhtT); Serial.print("C, ");
Serial.print(dhtH); Serial.print("%");
} else {
Serial.print("FAIL");
}
Serial.print(" | NTC1: "); Serial.print(ntc1C);
Serial.print("C | NTC2: "); Serial.print(ntc2C);
Serial.println("C");
delay(1000);
}