// =================== Library ==================== #include #include #include #include #include #include #include #include #include // =================== Konfigurasi MQTT TLS HiveMQ ==================== const char* mqtt_server = ""; // Masukkan URL mqtt cloudnya const int mqtt_port = 8883; const char* mqtt_user = ""; // Masukkan username const char* mqtt_pass = ""; // Masukkan password const char* mqtt_reset_topic = "ac/resetwifi"; // Untuk reset WiFi WiFiClientSecure secureClient; PubSubClient client(secureClient); // =================== IR AC ==================== const uint16_t kIrLed = 4; IRPanasonicAc ac(kIrLed); // =================== DHT ==================== #define DHTPIN 25 #define DHTTYPE DHT22 DHT dht(DHTPIN, DHTTYPE); unsigned long lastDHTRead = 0; const unsigned long dhtInterval = 5000; // =================== State AC ==================== uint8_t suhu = 25; uint8_t fanSpeed = kPanasonicAcFanAuto; bool power = false; bool swingOn = true; // =================== OTA ==================== void setup_ota() { ArduinoOTA.setHostname(""); // Masukkan Hostname OTA ArduinoOTA.setPassword(""); // Masukkan password OTA ArduinoOTA.onStart([]() { Serial.println("Mulai update OTA..."); }); ArduinoOTA.onEnd([]() { Serial.println("\nSelesai OTA"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress * 100) / total); }); ArduinoOTA.onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); }); ArduinoOTA.begin(); Serial.println("OTA Siap!"); } // =================== Kirim Sinyal IR ==================== void kirimIR() { if (power) { ac.on(); ac.setTemp(suhu); ac.setMode(kPanasonicAcCool); ac.setFan(fanSpeed); ac.setSwingVertical(swingOn ? kPanasonicAcSwingVAuto : kPanasonicAcSwingVMiddle); } else { ac.off(); } ac.send(); Serial.println("Sinyal IR dikirim."); } // =================== Callback MQTT ==================== void callback(char* topic, byte* payload, unsigned int length) { payload[length] = '\0'; String message = String((char*)payload); String tpc = String(topic); Serial.print("Pesan ["); Serial.print(tpc); Serial.print("]: "); Serial.println(message); if (tpc == "ac/power") { if (message == "on") { power = true; } else if (message == "off") { power = false; } kirimIR(); } else if (tpc == "ac/temp") { int temp = message.toInt(); if (temp >= 16 && temp <= 30) { suhu = temp; kirimIR(); } } else if (tpc == "ac/swing") { swingOn = (message == "on"); kirimIR(); } else if (tpc == "ac/fan") { if (message == "auto") fanSpeed = kPanasonicAcFanAuto; else if (message == "low") fanSpeed = kPanasonicAcFanMin; else if (message == "medium") fanSpeed = kPanasonicAcFanMed; else if (message == "high") fanSpeed = kPanasonicAcFanMax; kirimIR(); } else if (tpc == mqtt_reset_topic && message == "reset") { Serial.println("Reset WiFi via MQTT..."); WiFiManager wm; wm.resetSettings(); ESP.restart(); } } // =================== Reconnect MQTT ==================== void connectMQTT() { while (!client.connected()) { Serial.print("Menghubungkan ke MQTT..."); if (client.connect("ESP32Client", mqtt_user, mqtt_pass)) { Serial.println("Berhasil!"); client.subscribe("ac/power"); client.subscribe("ac/temp"); client.subscribe("ac/swing"); client.subscribe("ac/fan"); client.subscribe(mqtt_reset_topic); } else { Serial.print("Gagal, rc="); Serial.print(client.state()); Serial.println(" coba lagi 5 detik..."); delay(5000); } } } // =================== Setup ==================== void setup() { Serial.begin(115200); ac.begin(); dht.begin(); // Gunakan WiFiManager WiFiManager wm; if (!wm.autoConnect("ESP32_Config")) { Serial.println("Gagal konek, restart ESP..."); ESP.restart(); } // TLS: non-validasi sertifikat untuk sementara secureClient.setInsecure(); client.setServer(mqtt_server, mqtt_port); client.setCallback(callback); setup_ota(); } // =================== Loop ==================== void loop() { if (!client.connected()) { connectMQTT(); } client.loop(); ArduinoOTA.handle(); // Menangani OTA // Offset kalibrasi (jika sensor DHT22 tidak akurat) const float offsetTemp = -6.2; // sesuaikan dengan remote AC const float offsetHum = 0.0; // bisa disesuaikan jika perlu // Threshold monitoring suhu terhadap remote const float threshold = 1.0; // toleransi suhu ±1°C dari setpoint float targetRemote = suhu; // suhu yang disetel dari remote AC (via MQTT) // Baca dan kirim data DHT22 setiap interval if (millis() - lastDHTRead > dhtInterval) { lastDHTRead = millis(); float temp = dht.readTemperature(); float hum = dht.readHumidity(); if (!isnan(temp) && !isnan(hum)) { // Terapkan offset kalibrasi float calibratedTemp = temp + offsetTemp; float calibratedHum = hum + offsetHum; // Hitung status suhu terhadap setpoint String status; if (abs(calibratedTemp - targetRemote) <= threshold) { status = "sesuai"; } else { status = "belum sesuai"; } // Kirim payload ke MQTT String payload = "{\"suhu\":" + String(calibratedTemp, 1) + ",\"kelembapan\":" + String(calibratedHum, 1) + ",\"status\":\"" + status + "\"}"; client.publish("sensor/dht22", payload.c_str()); Serial.println("Dikirim: " + payload); } else { Serial.println("Gagal membaca sensor DHT22"); } } }