#include <LiquidCrystal_I2C.h>
#include "DHT.h"
// --- CONFIGURATION ---
#define DHTPIN 4 // Digital pin connected to the DHT sensor
#define DHTTYPE DHT22 // DHT 22 (AM2302)
// Initialize DHT sensor
DHT dht(DHTPIN, DHTTYPE);
// Initialize LCD (Address 0x27 is standard, change if yours is 0x3F)
int lcdColumns = 16;
int lcdRows = 2;
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);
// --- CUSTOM CHARACTER BITMAPS ---
byte pacmanOpen[] = { B01110, B11101, B11110, B11100, B11110, B11111, B01110, B00000 };
byte pacmanClosed[] = { B01110, B11111, B11111, B11111, B11111, B11111, B01110, B00000 };
byte ghost[] = { B01110, B11111, B10101, B11111, B11111, B11111, B10101, B00000 };
byte dot[] = { B00000, B00000, B00000, B00110, B00110, B00000, B00000, B00000 };
// A small degree symbol
byte degree[] = { B00110, B01001, B01001, B00110, B00000, B00000, B00000, B00000 };
void setup(){
Serial.begin(9600);
// Start Hardware
dht.begin();
lcd.init();
lcd.backlight();
// Create Custom Characters
lcd.createChar(0, pacmanOpen);
lcd.createChar(1, pacmanClosed);
lcd.createChar(2, ghost);
lcd.createChar(3, dot);
lcd.createChar(4, degree);
// Intro
lcd.setCursor(0, 0);
lcd.print("Sensors Init...");
delay(1000);
lcd.clear();
}
void loop(){
// --- 1. READ DATA ---
// Reading takes about 250ms
float h = dht.readHumidity();
float t = dht.readTemperature(); // Celsius
// Check if any reads failed
if (isnan(h) || isnan(t)) {
lcd.clear();
lcd.print("DHT Sensor Fail");
delay(2000);
return;
}
// --- 2. DISPLAY TEMP/HUMIDITY (Typewriter Effect) ---
lcd.clear();
// Construct Strings
String tempLine = "Temp: " + String(t, 1); // "Temp: 24.5"
String humLine = "Hum: " + String(h, 1) + "%";
// Print Top Row (Typewriter)
animTypewriter(tempLine, 0);
// Print Degree Symbol manually after the number
lcd.write(4);
lcd.print("C");
// Print Bottom Row (Typewriter)
animTypewriter(humLine, 1);
// Wait to let user read
delay(3000);
// --- 3. PACMAN WIPE (Cleans the screen) ---
animPacman();
lcd.clear();
// --- 4. CALCULATE HEAT INDEX (Real Feel) ---
float hic = dht.computeHeatIndex(t, h, false);
String hiLine1 = "Feels Like:";
String hiLine2 = String(hic, 1);
// --- 5. DISSOLVE EFFECT ---
// This function prints the text, waits, then vaporizes it
animDissolveHeatIndex(hiLine1, hiLine2);
delay(500);
}
// ------------------------------------------------
// ANIMATION FUNCTIONS
// ------------------------------------------------
// EFFECT 1: Typewriter
void animTypewriter(String text, int row) {
lcd.setCursor(0, row);
for (int i = 0; i < text.length(); i++) {
lcd.print(text.charAt(i));
delay(50); // Typing speed
}
}
// EFFECT 2: Pacman Chase (Used as a transition)
void animPacman() {
// 1. Fill bottom row with dots to eat
for(int i=0; i<16; i++) {
lcd.setCursor(i, 1);
lcd.write(3);
}
// 2. The Chase
for (int i = 0; i < 16; i++) {
// Draw Ghost
if (i > 0) {
lcd.setCursor(i - 1, 1);
lcd.write(2);
// Erase behind ghost
if (i > 1) {
lcd.setCursor(i - 2, 1);
lcd.print(" ");
}
}
// Draw Pacman
lcd.setCursor(i, 1);
lcd.write(0); // Open
delay(80);
lcd.setCursor(i, 1);
lcd.write(1); // Closed
delay(80);
}
}
// EFFECT 3: Dissolve (Specifically for Heat Index display)
void animDissolveHeatIndex(String line1, String line2) {
// Print the text normally first
lcd.setCursor(0, 0); lcd.print(line1);
lcd.setCursor(0, 1); lcd.print(line2);
lcd.write(4); lcd.print("C"); // Add degree symbol
delay(2500); // Hold the message
// Start Dissolving
int cleared[32];
for(int i=0; i<32; i++) cleared[i] = 0;
int totalChars = 32;
int erasedCount = 0;
while(erasedCount < totalChars) {
int r = random(0, 32);
if(cleared[r] == 0) {
int col = r % 16;
int row = (r < 16) ? 0 : 1;
lcd.setCursor(col, row);
lcd.print(" ");
cleared[r] = 1;
erasedCount++;
delay(15);
}
}
}