368 lines
9.1 KiB
Plaintext
368 lines
9.1 KiB
Plaintext
#include <Wire.h>
|
|
#include <LiquidCrystal_I2C.h>
|
|
#include <DHT.h>
|
|
#include <ESP8266WiFi.h>
|
|
#include <PubSubClient.h>
|
|
|
|
// Konfigurasi LCD
|
|
LiquidCrystal_I2C lcd(0x27, 16, 2);
|
|
|
|
// Konfigurasi DHT11
|
|
#define DHTPIN 2 // GPIO2 (D4)
|
|
#define DHTTYPE DHT11
|
|
DHT dht(DHTPIN, DHTTYPE);
|
|
|
|
// Konfigurasi MQ135
|
|
#define MQ135_PIN A0
|
|
float R0 = 76.63; // Nilai default, akan dikalibrasi ulang
|
|
|
|
// Konfigurasi Buzzer dan LED
|
|
#define BUZZER_PIN 12 // GPIO12 (D6)
|
|
#define LED_PIN 14 // GPIO14 (D5) - Pin untuk LED indikator (diubah ke D5)
|
|
#define CO2_THRESHOLD 90 // Threshold CO2 dalam ppm
|
|
#define TEMP_THRESHOLD 30 // Threshold suhu dalam °C
|
|
#define HUMID_THRESHOLD 80 // Threshold kelembaban dalam %
|
|
|
|
// Konfigurasi WiFi dan MQTT
|
|
const char* ssid = "SKK - STUDENT";
|
|
const char* password = "";
|
|
const char* mqtt_server = "103.124.138.170";
|
|
const int mqtt_port = 1883;
|
|
const char* mqtt_user = "USER_MQTT";
|
|
const char* mqtt_pass = "PASS_MQTT";
|
|
const char* topic_temp = "sensor/temperature";
|
|
const char* topic_humid = "sensor/humidity";
|
|
const char* topic_co2 = "sensor/co2";
|
|
const char* topic_control = "sensor/control";
|
|
const char* topic_status = "sensor/status";
|
|
const char* topic_alert = "sensor/alert";
|
|
|
|
WiFiClient espClient;
|
|
PubSubClient client(espClient);
|
|
|
|
// Variabel status sistem
|
|
bool systemEnabled = true;
|
|
unsigned long lastSensorUpdate = 0;
|
|
const long sensorInterval = 60000; // Interval pengiriman data sensor (ms)
|
|
|
|
void setup_wifi() {
|
|
delay(10);
|
|
Serial.println();
|
|
Serial.print("Connecting to ");
|
|
Serial.println(ssid);
|
|
|
|
WiFi.begin(ssid, password);
|
|
|
|
lcd.clear();
|
|
lcd.print("Connecting WiFi");
|
|
|
|
while (WiFi.status() != WL_CONNECTED) {
|
|
for(int i=0; i<10; i++) {
|
|
delay(500);
|
|
Serial.print(".");
|
|
lcd.print(".");
|
|
}
|
|
lcd.clear();
|
|
lcd.print("Retrying WiFi...");
|
|
}
|
|
|
|
Serial.println("");
|
|
Serial.println("WiFi connected");
|
|
Serial.println("IP address: ");
|
|
Serial.println(WiFi.localIP());
|
|
|
|
lcd.clear();
|
|
lcd.print("WiFi Connected");
|
|
lcd.setCursor(0, 1);
|
|
lcd.print(WiFi.localIP());
|
|
delay(2000);
|
|
}
|
|
|
|
void reconnect() {
|
|
while (!client.connected()) {
|
|
Serial.print("Attempting MQTT connection...");
|
|
|
|
if (client.connect("ESP8266Client", mqtt_user, mqtt_pass)) {
|
|
Serial.println("connected");
|
|
client.subscribe(topic_control);
|
|
Serial.println("Subscribed to control topic");
|
|
client.publish(topic_status, systemEnabled ? "ON" : "OFF", true);
|
|
} else {
|
|
Serial.print("failed, rc=");
|
|
Serial.print(client.state());
|
|
Serial.println(" try again in 5 seconds");
|
|
|
|
lcd.clear();
|
|
lcd.print("MQTT Fail");
|
|
lcd.setCursor(0, 1);
|
|
lcd.print("Retrying...");
|
|
|
|
delay(5000);
|
|
}
|
|
}
|
|
}
|
|
|
|
void callback(char* topic, byte* payload, unsigned int length) {
|
|
Serial.print("Message arrived [");
|
|
Serial.print(topic);
|
|
Serial.print("] ");
|
|
|
|
char message[length+1];
|
|
for (int i = 0; i < length; i++) {
|
|
message[i] = (char)payload[i];
|
|
}
|
|
message[length] = '\0';
|
|
Serial.println(message);
|
|
|
|
if (String(topic) == topic_control) {
|
|
if (strcmp(message, "ON") == 0) {
|
|
systemEnabled = true;
|
|
noTone(BUZZER_PIN); // Matikan buzzer saat sistem dihidupkan
|
|
digitalWrite(LED_PIN, LOW); // Matikan LED
|
|
lcd.clear();
|
|
lcd.print("System ON");
|
|
client.publish(topic_status, "ON", true);
|
|
Serial.println("System turned ON");
|
|
delay(1000);
|
|
}
|
|
else if (strcmp(message, "OFF") == 0) {
|
|
systemEnabled = false;
|
|
noTone(BUZZER_PIN); // Matikan buzzer saat sistem dimatikan
|
|
digitalWrite(LED_PIN, LOW); // Matikan LED
|
|
lcd.clear();
|
|
lcd.print("System OFF");
|
|
client.publish(topic_status, "OFF", true);
|
|
Serial.println("System turned OFF");
|
|
delay(1000);
|
|
}
|
|
}
|
|
}
|
|
//mengubah waktu kalibrasi
|
|
void calibrateR0() {
|
|
if (!systemEnabled) return;
|
|
|
|
Serial.println("Kalibrasi MQ135 dimulai...");
|
|
lcd.clear();
|
|
lcd.print("Kalibrasi MQ135");
|
|
lcd.setCursor(0, 1);
|
|
lcd.print("Udara bersih 5m");
|
|
//rubah pada waktu 300
|
|
for(int i = 0; i < 300; i++) {
|
|
delay(1000);
|
|
if(i % 30 == 0) {
|
|
Serial.print(".");
|
|
lcd.print(".");
|
|
}
|
|
if (!systemEnabled) {
|
|
Serial.println("Kalibrasi dibatalkan!");
|
|
lcd.clear();
|
|
lcd.print("Kalibrasi");
|
|
lcd.setCursor(0, 1);
|
|
lcd.print("Dibatalkan");
|
|
delay(2000);
|
|
return;
|
|
}
|
|
}
|
|
|
|
Serial.println("\nMengambil sampel...");
|
|
float sum = 0;
|
|
int validReadings = 0;
|
|
|
|
for (int i = 0; i < 100; i++) {
|
|
int rawValue = analogRead(MQ135_PIN);
|
|
if(rawValue < 50 || rawValue > 1000) {
|
|
continue;
|
|
}
|
|
|
|
float sensor_volt = rawValue * (3.3 / 1023.0);
|
|
float RS_air = (3.3 - sensor_volt) / sensor_volt;
|
|
sum += RS_air;
|
|
validReadings++;
|
|
delay(100);
|
|
|
|
if (!systemEnabled) {
|
|
Serial.println("Kalibrasi dibatalkan!");
|
|
lcd.clear();
|
|
lcd.print("Kalibrasi");
|
|
lcd.setCursor(0, 1);
|
|
lcd.print("Dibatalkan");
|
|
delay(2000);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(validReadings < 50) {
|
|
Serial.println("Gagal kalibrasi: Pembacaan tidak stabil");
|
|
lcd.clear();
|
|
lcd.print("Gagal Kalibrasi!");
|
|
delay(3000);
|
|
return;
|
|
}
|
|
|
|
R0 = sum / validReadings;
|
|
Serial.print("R0 terkalibrasi: ");
|
|
Serial.println(R0);
|
|
|
|
lcd.clear();
|
|
lcd.print("Kalibrasi Selesai");
|
|
lcd.setCursor(0, 1);
|
|
lcd.print("R0: ");
|
|
lcd.print(R0);
|
|
delay(3000);
|
|
}
|
|
|
|
void controlBuzzerAndLED(float temperature, float humidity, float co2) {
|
|
bool alertCondition = false;
|
|
String alertMessage = "";
|
|
|
|
if (co2 > CO2_THRESHOLD && co2 > 0) {
|
|
alertCondition = true;
|
|
alertMessage += "CO2 tinggi! ";
|
|
Serial.println("Peringatan: Level CO2 melebihi threshold!");
|
|
}
|
|
|
|
if (temperature > TEMP_THRESHOLD && temperature > 0) {
|
|
alertCondition = true;
|
|
alertMessage += "Suhu tinggi! ";
|
|
Serial.println("Peringatan: Suhu melebihi threshold!");
|
|
}
|
|
|
|
if (humidity > HUMID_THRESHOLD && humidity > 0) {
|
|
alertCondition = true;
|
|
alertMessage += "Kelembaban tinggi! ";
|
|
Serial.println("Peringatan: Kelembaban melebihi threshold!");
|
|
}
|
|
|
|
if (alertCondition && systemEnabled) {
|
|
tone(BUZZER_PIN, 1000); // Frekuensi 1 kHz
|
|
digitalWrite(LED_PIN, HIGH); // Nyalakan LED
|
|
lcd.setCursor(15, 0);
|
|
lcd.print("!");
|
|
|
|
if (alertMessage.length() > 0) {
|
|
client.publish(topic_alert, alertMessage.c_str());
|
|
}
|
|
} else {
|
|
noTone(BUZZER_PIN);
|
|
digitalWrite(LED_PIN, LOW); // Matikan LED
|
|
lcd.setCursor(15, 0);
|
|
lcd.print(" ");
|
|
}
|
|
}
|
|
|
|
void readAndSendSensorData() {
|
|
if (!systemEnabled) {
|
|
noTone(BUZZER_PIN);
|
|
digitalWrite(LED_PIN, LOW);
|
|
return;
|
|
}
|
|
|
|
float humidity = dht.readHumidity();
|
|
float temperature = dht.readTemperature();
|
|
int rawValue = analogRead(MQ135_PIN);
|
|
|
|
float sensor_volt = rawValue * (3.3 / 1023.0);
|
|
float RS_gas = (3.3 - sensor_volt) / sensor_volt;
|
|
float ratio = RS_gas / R0;
|
|
float ppm_CO2 = 116.6020682 * pow(ratio, -2.769034857);
|
|
|
|
float corrected_ppm = ppm_CO2;
|
|
if (!isnan(temperature) && !isnan(humidity)) {
|
|
corrected_ppm = ppm_CO2 * (1.0 + 0.0005*(25-temperature) + 0.0002*humidity);
|
|
}
|
|
|
|
if (isnan(humidity)) humidity = -1;
|
|
if (isnan(temperature)) temperature = -1;
|
|
if(rawValue < 50 || rawValue > 1000) corrected_ppm = -1;
|
|
|
|
controlBuzzerAndLED(temperature, humidity, corrected_ppm);
|
|
|
|
lcd.clear();
|
|
lcd.setCursor(0, 0);
|
|
lcd.print("S:");
|
|
lcd.print(systemEnabled ? "ON " : "OFF");
|
|
lcd.print(" T:");
|
|
lcd.print(temperature >= 0 ? temperature : -1, 1);
|
|
lcd.print("C");
|
|
|
|
lcd.setCursor(0, 1);
|
|
lcd.print("H:");
|
|
lcd.print(humidity >= 0 ? humidity : -1, 0);
|
|
lcd.print("% CO2:");
|
|
if(corrected_ppm < 0) {
|
|
lcd.print("Err");
|
|
} else {
|
|
lcd.print(corrected_ppm, 0);
|
|
}
|
|
|
|
char tempStr[10], humidStr[10], co2Str[10];
|
|
dtostrf(temperature, 4, 2, tempStr);
|
|
dtostrf(humidity, 4, 2, humidStr);
|
|
dtostrf(corrected_ppm, 4, 0, co2Str);
|
|
|
|
client.publish(topic_temp, tempStr);
|
|
client.publish(topic_humid, humidStr);
|
|
client.publish(topic_co2, co2Str);
|
|
|
|
Serial.print("Temperature: ");
|
|
Serial.print(tempStr);
|
|
Serial.print("C | Humidity: ");
|
|
Serial.print(humidStr);
|
|
Serial.print("% | CO2: ");
|
|
Serial.print(co2Str);
|
|
Serial.println("ppm");
|
|
}
|
|
|
|
void setup() {
|
|
Serial.begin(115200);
|
|
|
|
pinMode(BUZZER_PIN, OUTPUT);
|
|
pinMode(LED_PIN, OUTPUT);
|
|
digitalWrite(BUZZER_PIN, LOW);
|
|
digitalWrite(LED_PIN, LOW);
|
|
|
|
lcd.init();
|
|
lcd.backlight();
|
|
lcd.setCursor(0, 0);
|
|
lcd.print("Starting System...");
|
|
|
|
dht.begin();
|
|
|
|
int testVal = analogRead(MQ135_PIN);
|
|
if(testVal < 50) {
|
|
Serial.println("ERROR: Sensor MQ135 tidak terdeteksi!");
|
|
lcd.clear();
|
|
lcd.print("MQ135 Error!");
|
|
while(1) {
|
|
delay(1000);
|
|
Serial.println("Periksa koneksi dan reset board");
|
|
}
|
|
}
|
|
|
|
setup_wifi();
|
|
|
|
client.setServer(mqtt_server, mqtt_port);
|
|
client.setCallback(callback);
|
|
|
|
calibrateR0();
|
|
|
|
lcd.clear();
|
|
}
|
|
|
|
void loop() {
|
|
if (!client.connected()) {
|
|
reconnect();
|
|
}
|
|
client.loop();
|
|
|
|
lcd.setCursor(3, 0);
|
|
lcd.print(systemEnabled ? "ON " : "OFF");
|
|
|
|
unsigned long currentMillis = millis();
|
|
if (currentMillis - lastSensorUpdate >= sensorInterval && systemEnabled) {
|
|
lastSensorUpdate = currentMillis;
|
|
readAndSendSensorData();
|
|
}
|
|
|
|
delay(100);
|
|
} |