// ============================================================
// SMART TV SIMULATION — Wokwi + ESP32
// ============================================================
//
// COMPONENTS:
// - DHT22 → temperature & humidity sensor (GPIO 4)
// - IR Receiver → reads the remote control (GPIO 15)
// - IR Remote → the TV remote
// - LCD 16x2 I2C → TV screen display (SDA=21, SCL=22)
// - Green LED → power indicator (GPIO 2)
// - Red LED → temperature warning (GPIO 13)
// - Buzzer → audio feedback (GPIO 5)
//
// HOW TO USE:
// 1. Press Play in Wokwi to start the simulation
// 2. Use the IR Remote to control the TV
// ON / OFF / MUTE / VOL UP / VOL DOWN / CH UP / CH DOWN
// 4. Click the DHT22 and drag temperature above 35C or below 15C
// to trigger the temperature warning
//
// ============================================================
// ── SECTION 1: LIBRARIES ────────────────────────────────────
#include <DHT.h>
#include <LiquidCrystal_I2C.h>
#include <IRremoteESP8266.h>
#include <IRrecv.h>
#include <IRutils.h>
// ── SECTION 2: PIN DEFINITIONS ──────────────────────────────
#define DHT_PIN 4 // DHT22 data pin
#define DHT_TYPE DHT22
#define IR_PIN 15 // IR Receiver output pin
#define BUZZER_PIN 5 // Buzzer
#define LED_POWER 2 // Green LED (power on/off)
#define LED_WARN 13 // Red LED (temperature warning)
// ── SECTION 3: SETTINGS ─────────────────────────────────────
#define TEMP_HIGH 35.0 // Degrees C — triggers high temp warning
#define TEMP_LOW 15.0 // Degrees C — triggers low temp warning
// ── SECTION 4: IR REMOTE BUTTON CODES (NEC Protocol) ────────
// If buttons don't respond, check the Serial Monitor for the
// printed hex code and update the matching line below.
#define IR_POWER 0xFF629D
#define IR_VOL_UP 0xFFA857
#define IR_VOL_DOWN 0xFFE01F
#define IR_CH_UP 0xFF22DD
#define IR_CH_DOWN 0xFF02FD
#define IR_MUTE 0xFF9867
// ── SECTION 5: OBJECTS ──────────────────────────────────────
DHT dht(DHT_PIN, DHT_TYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2);
IRrecv irrecv(IR_PIN);
decode_results irResults;
// ── SECTION 6: TV STATE VARIABLES ───────────────────────────
bool tvOn = false; // Is the TV on or off?
int channel = 1; // Current channel (1–999)
int volume = 50; // Current volume (0–100)
bool muted = false; // Is the TV muted?
float temperature = 0; // Last temperature reading
float humidity = 0; // Last humidity reading
bool tempHigh = false; // Is temperature too high?
bool tempLow = false; // Is temperature too low?
unsigned long lastTempRead = 0;
unsigned long lastDisplay = 0;
// ============================================================
// SETUP — runs once when the simulation starts
// ============================================================
void setup() {
Serial.begin(115200);
// Set pin modes
pinMode(LED_POWER, OUTPUT);
pinMode(LED_WARN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
// Start sensors and display
dht.begin();
lcd.init();
lcd.backlight();
// Welcome screen
lcd.setCursor(3, 0);
lcd.print("SMART TV");
lcd.setCursor(2, 1);
lcd.print("Booting up..");
delay(2000);
lcd.clear();
// Start IR receiver
irrecv.enableIRIn();
// Print instructions to Serial Monitor
Serial.println("====================================");
Serial.println(" SMART TV — READY");
Serial.println("====================================");
Serial.println("Voice Commands (type in Serial):");
Serial.println(" ON — turn TV on");
Serial.println(" OFF — turn TV off");
Serial.println(" MUTE — toggle mute");
Serial.println(" VOL UP — raise volume");
Serial.println(" VOL DOWN — lower volume");
Serial.println(" CH UP — next channel");
Serial.println(" CH DOWN — previous channel");
Serial.println("====================================");
}
// ============================================================
// LOOP — runs repeatedly while the simulation is running
// ============================================================
void loop() {
// 1. Read temperature every 2 seconds
if (millis() - lastTempRead >= 2000) {
readTemperature();
lastTempRead = millis();
}
// 2. Check for IR remote button presses
if (irrecv.decode(&irResults)) {
uint32_t code = irResults.value;
if (code != 0xFFFFFFFF) { // 0xFFFFFFFF = button held down (repeat), ignore it
handleIR(code);
}
irrecv.resume(); // Ready to receive the next signal
}
// 3. Check for voice commands typed in Serial Monitor
if (Serial.available()) {
String cmd = Serial.readStringUntil('\n');
cmd.trim();
cmd.toUpperCase();
handleVoice(cmd);
}
// 4. Refresh the LCD display every 500ms
if (millis() - lastDisplay >= 500) {
updateDisplay();
lastDisplay = millis();
}
}
// ============================================================
// TEMPERATURE — reads DHT22 and checks thresholds
// ============================================================
void readTemperature() {
float t = dht.readTemperature();
float h = dht.readHumidity();
if (isnan(t)) return; // Sensor not ready yet
temperature = t;
humidity = h;
bool wasHigh = tempHigh;
bool wasLow = tempLow;
tempHigh = (temperature > TEMP_HIGH);
tempLow = (temperature < TEMP_LOW);
if (tempHigh && !wasHigh) {
// Just crossed above the high threshold
digitalWrite(LED_WARN, HIGH);
alertBeep(3);
Serial.print("WARNING: Temperature too HIGH! ");
Serial.print(temperature);
Serial.println("C");
} else if (tempLow && !wasLow) {
// Just crossed below the low threshold
digitalWrite(LED_WARN, HIGH);
alertBeep(3);
Serial.print("WARNING: Temperature too LOW! ");
Serial.print(temperature);
Serial.println("C");
} else if (!tempHigh && !tempLow) {
// Temperature is back to normal
digitalWrite(LED_WARN, LOW);
}
}
// ============================================================
// IR REMOTE — handles button presses from the remote
// ============================================================
void handleIR(uint32_t code) {
Serial.print("IR Received: 0x");
Serial.println(code, HEX); // Prints the code — useful for finding unmapped buttons
switch (code) {
case IR_POWER: togglePower(); break;
case IR_VOL_UP: changeVolume(+5); break;
case IR_VOL_DOWN: changeVolume(-5); break;
case IR_CH_UP: changeChannel(+1); break;
case IR_CH_DOWN: changeChannel(-1); break;
case IR_MUTE: toggleMute(); break;
default:
Serial.println(" (button not mapped — copy the hex code above into the #define section)");
}
}
// ============================================================
// VOICE COMMANDS — handles text typed in Serial Monitor
// ============================================================
void handleVoice(String cmd) {
Serial.print("Voice Command: \"");
Serial.print(cmd);
Serial.println("\"");
if (cmd == "ON" || cmd == "TURN ON") { if (!tvOn) togglePower(); }
else if (cmd == "OFF" || cmd == "TURN OFF") { if (tvOn) togglePower(); }
else if (cmd == "MUTE" || cmd == "UNMUTE") toggleMute();
else if (cmd == "VOL UP" || cmd == "VOLUME UP") changeVolume(+10);
else if (cmd == "VOL DOWN" || cmd == "VOLUME DOWN") changeVolume(-10);
else if (cmd == "CH UP" || cmd == "CHANNEL UP") changeChannel(+1);
else if (cmd == "CH DOWN" || cmd == "CHANNEL DOWN")changeChannel(-1);
else Serial.println(" Unknown command. Check the list above.");
}
// ============================================================
// TV CONTROLS
// ============================================================
void togglePower() {
tvOn = !tvOn;
digitalWrite(LED_POWER, tvOn ? HIGH : LOW);
if (tvOn) {
lcd.backlight();
beep(200);
Serial.println("TV → ON");
} else {
lcd.noBacklight();
lcd.clear();
beep(200);
delay(100);
beep(200);
Serial.println("TV → OFF");
}
}
void changeVolume(int delta) {
if (!tvOn) return;
volume = constrain(volume + delta, 0, 100);
beep(80);
Serial.print("Volume: ");
Serial.println(volume);
}
void changeChannel(int delta) {
if (!tvOn) return;
channel += delta;
if (channel > 999) channel = 1;
if (channel < 1) channel = 999;
beep(80);
Serial.print("Channel: ");
Serial.println(channel);
}
void toggleMute() {
if (!tvOn) return;
muted = !muted;
beep(150);
Serial.print("Mute: ");
Serial.println(muted ? "ON" : "OFF");
}
// ============================================================
// DISPLAY — updates the LCD screen
// ============================================================
void updateDisplay() {
if (!tvOn) return;
// ── Row 0: Channel and Volume ──
lcd.setCursor(0, 0);
lcd.print("CH:");
if (channel < 10) lcd.print(" ");
else if (channel < 100) lcd.print(" ");
lcd.print(channel);
lcd.print(" ");
if (muted) {
lcd.print(" [MUTED]");
} else {
lcd.print("VOL:");
if (volume < 10) lcd.print(" ");
lcd.print(volume);
lcd.print("% ");
}
// ── Row 1: Temperature status ──
lcd.setCursor(0, 1);
if (tempHigh) {
lcd.print("!HOT ");
lcd.print((int)temperature);
lcd.print("C WARN! ");
} else if (tempLow) {
lcd.print("!COLD ");
lcd.print((int)temperature);
lcd.print("C WARN! ");
} else {
lcd.print("Temp:");
lcd.print((int)temperature);
lcd.print("C OK ");
}
}
// ============================================================
// HELPERS
// ============================================================
void beep(int ms) {
// Short beep for button feedback
digitalWrite(BUZZER_PIN, HIGH);
delay(ms);
digitalWrite(BUZZER_PIN, LOW);
}
void alertBeep(int times) {
// Repeated beep for temperature warnings
for (int i = 0; i < times; i++) {
beep(250);
delay(100);
}
}
// ============================================================
// END OF FILE
// ============================================================