215 lines
5.7 KiB
C++
215 lines
5.7 KiB
C++
// =================== Library ====================
|
|
#include <WiFi.h>
|
|
#include <WiFiClientSecure.h>
|
|
#include <WiFiManager.h>
|
|
#include <PubSubClient.h>
|
|
#include <IRremoteESP8266.h>
|
|
#include <IRsend.h>
|
|
#include <ir_Panasonic.h>
|
|
#include <DHT.h>
|
|
#include <ArduinoOTA.h>
|
|
|
|
// =================== Konfigurasi MQTT TLS HiveMQ ====================
|
|
const char* mqtt_server = "0b5fa203aa8240e290978c7e42ed2d8b.s1.eu.hivemq.cloud";
|
|
const int mqtt_port = 8883;
|
|
const char* mqtt_user = "acremote";
|
|
const char* mqtt_pass = "@Remote123";
|
|
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("acremote");
|
|
ArduinoOTA.setPassword("@Remote123");
|
|
|
|
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");
|
|
}
|
|
}
|
|
}
|
|
|