/*
Write the code in comment, and complete the
'if' statement in Control() and printWarn()
*/
#include "DHTesp.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <PubSubClient.h>
// ===== CLOUD =====
#include "WiFi.h"
#include "ThingSpeak.h"
// ===== Cloud =====
const char* WIFI_NAME = "Wokwi-GUEST";
const char* WIFI_PASSWORD = "";
const int myChannelNumber = 2737430;
const char* writeApiKey = "ZXXSRYTN2GBGMF3B";
const char* readApiKey = "AV9VVJHO8T1FW0US";
const char* server = "api.thingspeak.com";
// ------ PIN ---------
const int DHT_pin = 15;
const int photoresistor_sensor = 32;
const int led_pin = 12;
const int button_pin = 17;
const int buzzer_pin = 18;
const int relay_pin = 33;
const int trig_pin = 5;
const int echo_pin = 4;
#define TdsSensorPin A0
#define VREF 3.3 // Arduino uses 5V as reference voltage
#define SCOUNT 30 // sum of sample point
int analogBuffer[SCOUNT]; // store the analog value in the array, read from ADC
int analogBufferTemp[SCOUNT];
int analogBufferIndex = 0;
int copyIndex = 0;
float averageVoltage = 0;
float tdsValue = 0;
float temperature = 0;
const int oneWireBus = 19; // Arduino analog pin where the DS18B20 is connected to
OneWire oneWire(oneWireBus); // Setup a oneWire instance to communicate with any OneWire devices
DallasTemperature sensors(&oneWire); // Pass our oneWire reference to Dallas Temperature sensor
// ===== CLOUD + MQTT =====
WiFiClient client, mClient;
PubSubClient mqttClient(mClient);
const char* mqttServer = "broker.hivemq.com";
const int mqttPort = 1883;
// ----- Device -------
DHTesp dhtSensor;
LiquidCrystal_I2C lcd(0x27, 16, 2);
// ----- Constant -----
const float max_temp = 35;
const float min_temp = 20;
const float max_level = 30;
const float min_level = 15;
const float max_tds = 200;
const float min_tds = 0;
// ------ Global var. ------
String lastWarn = ".";
float lastArgv = 100;
int turn = 0;
const int temperatureField = 1;
const int waterLevelField = 2;
const int TdsField = 3;
const int photonField = 5;
const int waterRecommendField = 6;
bool ledState = false; // Trạng thái hiện tại của LED (false = tắt, true = bật)
int lastButtonState = LOW; // Trạng thái nút nhấn ở lần đọc trước
int relayState = LOW;
unsigned long lastWrite = 0;
// ---- Prototype -----
void Control();
float getTemp();
float getLevel(float max_level);
void printWarn(String, float argv);
int getMedianNum(int bArray[], int iFilterLen);
float getTDSValue();
void connectWifi();
void sendToCloud(float temp, float waterLV, float lux);
void mqttCallback(char* topic, byte* payload, unsigned int length);
void connectMqttServer();
// ------- Setup ------
void setup() {
Serial.begin(115200);
dhtSensor.setup(DHT_pin, DHTesp::DHT22);
lcd.init();
delay(100);
lcd.backlight();
pinMode(photoresistor_sensor, INPUT);
pinMode(led_pin, OUTPUT);
pinMode(button_pin, INPUT);
pinMode(relay_pin, OUTPUT);
pinMode(buzzer_pin, OUTPUT);
pinMode(TdsSensorPin, INPUT);
pinMode(trig_pin, OUTPUT);
pinMode(echo_pin, INPUT);
connectWifi();
ThingSpeak.begin(client);
sensors.begin();
mqttClient.setServer(mqttServer, mqttPort);
mqttClient.setCallback(mqttCallback);
}
// ------- Loop -------
void loop() {
if (!mqttClient.connected()){
connectMqttServer();
}
mqttClient.loop();
Control();
delay(2000);
}
// -------- Implement ---------
void Control() {
float temp = getTemp();
relay_control(digitalRead(button_pin));
float waterLV = getLevel(max_level);
float lux = getLight();
float TdsValue = getTDSValue();
float waterRecommendValue = ThingSpeak.readFloatField(myChannelNumber, waterRecommendField, readApiKey);
// Hàm để bật tắt đèn tự động
auto_Light(lux);
if (temp >= max_temp || temp <= min_temp) {
printWarn("temp", temp);
led();
buzzer();
}
else if (waterLV >= max_level || waterLV <= min_level) {
printWarn("water", waterLV);
led();
buzzer();
}
else if (TdsValue > max_tds || TdsValue < min_tds) {
printWarn("tds", TdsValue);
led();
buzzer();
}
/*
Your 'if' here
*/
else {
printWarn("", waterLV);
led();
}
sendToCloud(TdsValue, temp, waterLV, lux, waterRecommendValue);
}
// ================== Cloud function =====================
void sendToCloud(float tdsValue, float temp, float waterLV, float lux, float waterRecommend) {
// ===== SEND DATA TO CLOUD HERE =====
if ((millis() - lastWrite) > 15000 && tdsValue >= 0) {
Serial.println("===== INFORMATION =====");
Serial.println("TDSValue: " + String(tdsValue, 2));
Serial.println("---");
Serial.println("Temp: " + String(temp, 2) + "°C");
Serial.println("---");
Serial.println("WaterLV: " + String(waterLV, 2));
Serial.println("---");
Serial.println("PhotoValue: " + String(lux, 2));
Serial.println("---");
// Set all field for write together
ThingSpeak.setField(TdsField, tdsValue);
ThingSpeak.setField(temperatureField, temp);
ThingSpeak.setField(waterLevelField, waterLV);
ThingSpeak.setField(photonField, lux);
ThingSpeak.setField(waterRecommendField, waterRecommend);
ThingSpeak.writeFields(myChannelNumber, writeApiKey);
lastWrite = millis();
}
}
// =============== led =================
void led(){
digitalWrite(led_pin, HIGH);
delay(1000);
digitalWrite(led_pin, LOW);
delay(1000);
}
// ============== buzzer ===============
void buzzer() {
tone(buzzer_pin, 100);
delay(1000);
noTone(buzzer_pin);
delay(1000);
}
// ============== relay ===============
void relay_control(int buttonState) {
if (buttonState != lastButtonState) {
if (buttonState == LOW) {
if (digitalRead(relay_pin) == HIGH) {
digitalWrite(relay_pin, LOW);
}
else {
digitalWrite(relay_pin, HIGH);
}
}
lastButtonState = buttonState;
}
}
// ============== light sensor ===============
float getLight(){
return analogRead(photoresistor_sensor);
}
void auto_Light(float lux){
float lux_now = map(lux, 0, 1023, 0, 500);
// Bật hoặc tắt relay dựa trên giá trị lux
if (lux_now < 300) {
digitalWrite(relay_pin, LOW); // Đóng relay (bật đèn)
Serial.println("Relay ON - Light ON");
} else if (lux_now > 500) {
digitalWrite(relay_pin, HIGH); // Ngắt relay (tắt đèn)
Serial.println("Relay OFF - Light OFF");
} else {
Serial.println("Relay state unchanged (lux in range 300-500).");
}
}
// ============== temperature sensor ===============
float getTemp() {
TempAndHumidity data = dhtSensor.getTempAndHumidity();
return data.temperature;
}
// ============== water-level sensor ===============
float getLevel(float max_level) {
digitalWrite(trig_pin, LOW);
delayMicroseconds(2);
digitalWrite(trig_pin, HIGH);
delayMicroseconds(10);
digitalWrite(trig_pin, LOW);
float duration = pulseIn(echo_pin, HIGH);
float distanceCm = map(duration * 0.034 / 2, 0, 400, 0, 30);
return max_level - distanceCm;
}
// ============== warning on LCD ===============
void printWarn(String warn, float argv) {
// To avoid screen flickers
if (warn == lastWarn && lastArgv == argv)
return;
lastWarn = warn;
lastArgv = argv;
lcd.clear();
lcd.setCursor(0, 0);
if (warn == "temp") {
lcd.print("Temp. warning!");
lcd.setCursor(0, 1);
lcd.print("Now temp ");
lcd.print(argv, 1);
lcd.print("\'C");
}
else if (warn == "water") {
lcd.print("WaterLV warning!");
lcd.setCursor(0, 1);
lcd.print("Now level ");
lcd.print(argv, 1);
lcd.print("cm");
}
else if (warn == "tds") {
lcd.print("TDS warning!");
lcd.setCursor(0, 1);
lcd.print("Now TDS ");
lcd.print(argv, 1);
lcd.print("ppm");
}
else if (warn == "") {
lcd.print("Good!");
lcd.setCursor(0, 1);
lcd.print("Water lv: ");
lcd.print(argv, 1);
lcd.print("cm");
}
}
// =================== TDS sensor ===================
int getMedianNum(int bArray[], int iFilterLen) {
int bTab[iFilterLen];
for (byte i = 0; i < iFilterLen; i++)
bTab[i] = bArray[i];
int i, j, bTemp;
for (j = 0; j < iFilterLen - 1; j++) {
for (i = 0; i < iFilterLen - j - 1; i++) {
if (bTab[i] > bTab[i + 1]) {
bTemp = bTab[i];
bTab[i] = bTab[i + 1];
bTab[i + 1] = bTemp;
}
}
}
if ((iFilterLen & 1) > 0)
bTemp = bTab[(iFilterLen - 1) / 2];
else
bTemp = (bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2;
return bTemp;
}
float getTDSValue() {
sensors.requestTemperatures();
float temperature = sensors.getTempCByIndex(0);
static unsigned long analogSampleTimepoint = millis();
if (millis() - analogSampleTimepoint > 40U) {
analogSampleTimepoint = millis();
analogBuffer[analogBufferIndex] = analogRead(TdsSensorPin);
analogBufferIndex++;
if (analogBufferIndex == SCOUNT)
analogBufferIndex = 0;
}
static unsigned long printTimepoint = millis();
if (millis() - printTimepoint > 800U) {
printTimepoint = millis();
for (copyIndex = 0; copyIndex < SCOUNT; copyIndex++)
analogBufferTemp[copyIndex] = analogBuffer[copyIndex];
averageVoltage = getMedianNum(analogBufferTemp, SCOUNT) * (float)VREF / 1024.0;
float compensationCoefficient = 1.0 + 0.02 * (temperature - 25.0);
float compensationVolatge = averageVoltage / compensationCoefficient;
tdsValue = (133.42 * compensationVolatge * compensationVolatge * compensationVolatge - 255.86 * compensationVolatge * compensationVolatge + 857.39 * compensationVolatge) * 0.5;
return tdsValue;
}
return 0;
}
// ============== WiFi ===============
void connectWifi() {
WiFi.begin(WIFI_NAME, WIFI_PASSWORD);
delay(100);
Serial.print("Connecting");
while (WiFi.status() != WL_CONNECTED){
delay(500);
Serial.print(".");
}
Serial.println("\nWifi connected !");
Serial.println("Local IP: " + String(WiFi.localIP()));
WiFi.mode(WIFI_STA);
}
// ============== MQTT ===============
void mqttCallback(char* topic, byte* payload, unsigned int length) {
if (payload[0] == 0 + 48) {
digitalWrite(relay_pin, LOW);
}
else if (payload[0] == 1 + 48) {
digitalWrite(relay_pin, HIGH);
}
}
void connectMqttServer() {
while(!mqttClient.connect("iot-nhom14")){
delay(3000);
}
Serial.println("Connected to MQTT!");
mqttClient.subscribe("/iotnhom14/UV_Lamp");
}