Home IoT Hub Series · 19
[Part 19] Cool the room only when someone is there - PIR-based automatic AC control
Combine PIR presence, DHT22 temperature, and IR output for automatic cooling.
This part combines presence, temperature, and IR control. The node decides when cooling is needed instead of only reporting a sensor value.
Use cooldown timing so the air conditioner does not turn on and off repeatedly. Automation should be calm, not nervous.
![[Part 19] Cool the room only when someone is there - PIR-based automatic AC control hero image](/iot-lab/assets/automatic-air-conditioner-control-hero.png)
This article is part of the Home IoT Hub system connected to the central NodeMCU server built in Part 2: Building the Brain. This automation node combines PIR, DHT22, and IR control so cooling decisions run only when a person is present. The collected data is sent over the local
IoT_Hub_Net network and updates slot 1 for indoor temperature and slot 4 for air-conditioner state on the central server (/set?no1=temp&no4=state), becoming part of the decision pipeline for the 20-channel smart-home controller.Parts and cost
| Part | Qty | Unit price |
|---|---|---|
| HC-SR501 PIR sensor | 1 pc | $0.70 |
| Jumper wires 3 pc | — | — |
| Added total | $0.70 |
Pin wiring
Full code
PIR = person detected? AND DHT22 temp > 26℃? │ │ └──── YES ──────────┘ │ /set?no1=temp&no2=humidity&no4=ON │ The brain sends AC ON through the IR LED
#include <ESP8266WiFi.h> #include <ESP8266HTTPClient.h> #include <DHT.h> const char* ssid = "IoT_Hub_Net"; const char* password = "iothub1234"; const char* hubURL = "http://192.168.1.1"; #define DHTPIN 5 // D1 #define DHTTYPE DHT22 #define PIR_PIN 14 // D5 #define TEMP_ON 26.0 // turn AC on at 26 C or higher #define TEMP_OFF 24.0 // turn AC off at 24 C or lower #define PIR_TIMEOUT 300000 // treat as empty if no motion for 5 minutes #define COOLDOWN 300000 // 5-minute cooldown after AC ON/OFF change #define INTERVAL 5000 DHT dht(DHTPIN, DHTTYPE); bool acOn = false; unsigned long lastMotion = 0; unsigned long lastAcToggle = 0; void setup() { Serial.begin(115200); dht.begin(); pinMode(PIR_PIN, INPUT); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); Serial.print("Connecting to IoT_Hub_Net"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nConnected! Smart AC ready."); } void loop() { // ── sensor note── float temp = dht.readTemperature(); float hum = dht.readHumidity(); bool motion = digitalRead(PIR_PIN); // HIGH=note if (isnan(temp) || isnan(hum)) { Serial.println("DHT22 read failed"); delay(2000); return; } // note if (motion) lastMotion = millis(); // ── note── unsigned long now = millis(); bool occupied = (now - lastMotion < PIR_TIMEOUT); // note= note bool tooHot = (temp > TEMP_ON); bool coolEnough = (temp < TEMP_OFF); // note if (now - lastAcToggle < COOLDOWN) { // note } else { if (occupied && tooHot && !acOn) { // note acOn = true; lastAcToggle = now; sendAcCommand("ON"); Serial.println(">>> AC AUTO ON (hot + occupied)"); } else if ((!occupied || coolEnough) && acOn) { // no person or cool enough, AC OFF acOn = false; lastAcToggle = now; sendAcCommand("OFF"); Serial.println(">>> AC AUTO OFF (empty or cool enough)"); } } // ── note── String state = acOn ? "ON" : "OFF"; Serial.printf("Temp: %.1f C, Hum: %.1f %%, Motion: %s, AC: %s\n", temp, hum, motion ? "YES" : "no", state.c_str()); WiFiClient client; HTTPClient http; String url = String(hubURL) + "/set?no1=" + String(temp) + "&no2=" + String(hum); // AC statusnote // note url = url + "&no4=" + state; http.begin(client, url); int code = http.GET(); http.end(); Serial.print("HTTP "); Serial.print(code); Serial.print(" -> "); Serial.println(url); Serial.println(); delay(INTERVAL); } // ── AC ON/OFF note── void sendAcCommand(String cmd) { WiFiClient client; HTTPClient http; String url = String(hubURL) + "/set?no4=" + cmd; http.begin(client, url); http.GET(); http.end(); Serial.println("AC COMMAND -> " + url); }
Build notes
- Walk into the room, raise the temperature condition for testing, and confirm the AC slot changes only when both conditions are met.
- Power on the hub brain first so the node can join
IoT_Hub_Net. - Use the same slot number written in the source code.
- Open the serial monitor at 115200 baud and confirm
HTTP 200. - If the value does not appear on the hub, recheck wiring, GPIO number, and Wi-Fi connection.
Field operating checkpoints: troubleshooting, tips, and FAQ
The node code can look short, but real home installation is affected by placement, power, Wi-Fi quality, and sensor noise. Check these points before letting the node become a decision input for the brain server.
| Symptom | Likely cause | Field fix |
|---|---|---|
| The AC turns off while someone is still there | PIR sensors do not detect a stationary person for long | Keep a 10-20 minute hold time after last motion and do not turn off immediately from temperature alone. |
| Curtains or pets trigger it | The PIR field of view is wide and moving heat sources look like people | Aim the sensor toward the human path and filter out very short detections. |
| Cooling turns on and off repeatedly | A single temperature threshold causes flapping near the boundary | Use hysteresis, such as ON at 28°C and OFF at 26°C. |
| IR command is sent but cooling does not start | The AC missed the signal or current mode differs from assumed state | After IR transmit, verify outlet temperature change or slot 4 state after a short delay. |
Serial Monitor
After uploading, open Tools → Serial Monitor in the Arduino IDE and set the baud rate to 115200. The following is an example Serial Monitor flow for checking normal operation. This is not a real screenshot. It shows presence, room temperature, and AC state being combined into an automatic control decision.
[BOOT] Home IoT Node #19 - Auto AC controller [INPUT] room_temp(no1)=28.4C presence=YES ac_state(no4)=OFF [RULE] temp_high=true, person_present=true, cooldown_guard=PASS [COMMAND] AC_ON via IR [HTTP] GET /set?no4=1 [HUB] 200 OK - slot no4=AC_ON [LOOP] next decision in 60000 ms
- If
Connectedorconnectedappears, the Wi-Fi step passed. - If
HTTP 200or200 OKappears, the value reached the brain server. - If the value does not update, check both the slot number in the URL and the sensor wiring.
This article is part of the 20-channel Home IoT system built from the Part 2 central brain server and the distributed edge nodes in Parts 3-19. Use this map to check the slot and sensor flow across the series.
[Part 1] Home IoT Hub overview[Part 2] Central brain server · slots 1-20[Part 3] Stop guessing room comfort · slots 1/2[Part 4] Did I close the door? · slots 9[Part 5] Is the fridge really cooling? · slots 12[Part 6] Should I open the window? · slots 3[Part 7] Stop bathroom mold before it starts · slots 19[Part 8] Is the boiler actually running? · slots 5/17[Part 9] Did I leave the gas stove on? · slots 6[Part 10] Get warned before gas smell becomes obvious · slots 7[Part 11] Catch flame signs while away from home · slots 8[Part 12] Is bad air making you foggy? · slots 13/14[Part 13] Why is the power bill so high? · slots 15[Part 14] Is water leaking, and how much are we using? · slots 16[Part 15] Do not leave windows open in the rain · slots 18[Part 16] Are the lights off and the door locked? · slots 11/10[Part 17] Control the air conditioner from the IoT hub · slots 4[Part 18] Is the dog bowl empty? · slots 20[Part 19] Cool the room only when someone is there · slots 1/4[Part 20] The house finally fits on one screen · slots all