/*
README
* Arduino Pin usage
04 : LED wifi status front box (Actived when wifi is connected)
02 : Buzzer (Actived once when wifi is connected)
23 : DHT11 sensor
16 : Water temperature sensor A
17 : Sprayer pump
18 : Water Flow sensor
19 : Water temperature B
25 : LED wifi is connected (on board)
32 : LED wifi is disconnect (on board)
*/
#define BLYNK_PRINT Serial
#define BLYNK_TEMPLATE_ID "TMPL6imZyoDXH"
#define BLYNK_TEMPLATE_NAME "Hydroponic system"
#define BLYNK_AUTH_TOKEN "zqyykiXn8cgjGQmnATa3BteiLm1E9PBG"
#include <WiFi.h>
#include <DHT.h>
#include <Wire.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <BlynkSimpleEsp32.h>
#include <ezTime.h>
#include <TridentTD_LineNotify.h>
#include <FlowSensor.h> // Install FlowSensor by hafidhh
#include <BH1750.h> // Install BH1750 by Christopher Law
#include <PubSubClient.h>
#include <ArduinoJson.h> // Include ArduinoJson library for JSON formatting
#define LINE_TOKEN "FZqvnTwcXx7OqezlrGxToNRSntwn6eQR2gSY5MvZMDN"
#define ssid "mac"
#define password ""
// MQTT broker information
const char* mqtt_server = "0.tcp.ap.ngrok.io"; // Node-RED server IP
const int mqtt_port = 16020; // MQTT port (default is 1883)
// Create Wi-Fi and MQTT client objects
WiFiClient espClient;
PubSubClient client(espClient);
Timezone local;
BlynkTimer timer;
#define DHT_SENSOR_PIN 23
#define DHT_SENSOR_TYPE DHT11
DHT dht(DHT_SENSOR_PIN, DHT_SENSOR_TYPE);
// Water Temperature A
#define ONE_WIRE_BUS_WaterTemp_A 16 //Define water sensor 18B20 to pin 16
OneWire oneWireA(ONE_WIRE_BUS_WaterTemp_A);
DallasTemperature waterTempSensorA(&oneWireA);
// Water Temperature B
#define ONE_WIRE_BUS_WaterTemp_B 19 //Define water sensor 18B20 to pin 19
OneWire oneWireB(ONE_WIRE_BUS_WaterTemp_B);
DallasTemperature waterTempSensorB(&oneWireB);
// Water flow sensor
uint16_t waterFlowSensorType = YFS201;
uint8_t waterFlowSensorPin = 18;
FlowSensor waterFlowSensor(waterFlowSensorType, waterFlowSensorPin);
// Light meter
BH1750 lightMeter;
void IRAM_ATTR count() {
waterFlowSensor.count();
}
// Define sprayer pump relay pin 17
int switch_sprayer_pump = 17;
int ledConnect_onBoard = 25;
int ledDisConnect_onBoard = 32;
int ledConnect_Front = 4;
int Buzzer = 2;
unsigned long lastReadTime = 0;
unsigned long lastSendTime = 0;
const unsigned long readInterval = 100;
const unsigned long sendInterval = 5000;
int systemMode;
const char* timestamp;
void printClock() {
Serial.println("Time: " + local.dateTime());
}
BLYNK_WRITE(V2) {
systemMode = param.asInt();
if (systemMode == 0) {
Serial.println("System Mode: Auto");
} else {
Serial.println("System Mode: Manual");
}
}
BLYNK_WRITE(V8) {
if (param.asInt() == 1) {
LINE.notify("เติมชีวภัณฑ์ Bacillus subtilis ควบคุมโรครากเน่า\n\n\
- วิธีการใช้\n\
การเตรียมเพื่อใช้ทันที: ใช้ชีวภัณฑ์ 100 กรัมต่อสารละลายในระบบปลูก 100 ลิตร เมื่อย้ายปลูก และถ้ามีอาการรากเน่าโคนเน่าใส่เพิ่มทุก 7 วัน\n\nเติมปุ๋ยน้ำ AB\n\
ปุ๋ยน้ำ A ใส่ 3 cc ต่อน้ำ 1 ลิตร\n\
ปุ๋ยน้ำ B ใส่ 3 cc ต่อน้ำ 1 ลิตร");
}
}
BLYNK_CONNECTED() {
Blynk.sendInternal("utc", "time");
Blynk.sendInternal("utc", "tz_rule");
}
BLYNK_WRITE(InternalPinUTC) {
String cmd = param[0].asStr();
if (cmd == "time") {
const uint64_t utc_time = param[1].asLongLong();
UTC.setTime(utc_time / 1000, utc_time % 1000);
Serial.print("Unix time (UTC): ");
Serial.println(utc_time);
} else if (cmd == "tz_rule") {
String tz_rule = param[1].asStr();
local.setPosix(tz_rule);
Serial.print("POSIX TZ rule: ");
Serial.println(tz_rule);
}
}
BLYNK_WRITE(V7) {
TimeInputParam t(param);
if (t.hasStartTime()) {
Serial.println(String("Start: ") + t.getStartHour() + ":" + t.getStartMinute() + ":" + t.getStartSecond());
} else if (t.isStartSunrise()) {
Serial.println("Start at sunrise");
} else if (t.isStartSunset()) {
Serial.println("Start at sunset");
}
if (t.hasStopTime()) {
Serial.println(String("Stop: ") + t.getStopHour() + ":" + t.getStopMinute() + ":" + t.getStopSecond());
} else if (t.isStopSunrise()) {
Serial.println("Stop at sunrise");
} else if (t.isStopSunset()) {
Serial.println("Stop at sunset");
}
Serial.println(String("Time zone: ") + t.getTZ());
Serial.println(String("Time zone offset: ") + t.getTZ_Offset());
for (int i = 1; i <= 7; i++) {
if (t.isWeekdaySelected(i)) {
Serial.println(String("Day ") + i + " is selected");
}
}
Serial.println();
}
void WIFI_Connect() {
digitalWrite(ledDisConnect_onBoard, HIGH);
digitalWrite(ledConnect_onBoard, LOW);
digitalWrite(ledConnect_Front, LOW);
WiFi.disconnect();
Serial.println("Booting Sketch...");
WiFi.mode(WIFI_OFF);
delay(1000);
WiFi.mode(WIFI_AP_STA);
WiFi.begin(ssid, password);
for (int i = 0; i < 10; i++) {
if (WiFi.status() != WL_CONNECTED) {
delay(250);
digitalWrite(ledDisConnect_onBoard, LOW);
digitalWrite(ledConnect_onBoard, LOW);
digitalWrite(ledConnect_Front, LOW);
Serial.print(".");
delay(250);
digitalWrite(ledDisConnect_onBoard, HIGH);
digitalWrite(ledConnect_onBoard, LOW);
delay(250);
Serial.println("Device is disconnected!");
}
}
digitalWrite(ledDisConnect_onBoard, LOW);
digitalWrite(ledConnect_onBoard, HIGH);
digitalWrite(ledConnect_Front, HIGH);
}
void reconnect() {
// Attempt to connect to the MQTT broker
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
if (client.connect("ESP32Client")) {
Serial.println("connected");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void setup() {
Serial.begin(9600);
Wire.begin();
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, password);
LINE.setToken(LINE_TOKEN);
dht.begin();
lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE);
waterTempSensorA.begin();
waterTempSensorB.begin();
waterFlowSensor.begin(count);
client.setServer(mqtt_server, mqtt_port); // Set MQTT server
// timer.setInterval(10000, printClock);
pinMode(switch_sprayer_pump, OUTPUT);
pinMode(ledConnect_onBoard, OUTPUT);
pinMode(ledDisConnect_onBoard, OUTPUT);
pinMode(ledConnect_Front, OUTPUT);
pinMode(Buzzer, OUTPUT);
WIFI_Connect();
digitalWrite(Buzzer, HIGH);
delay(300);
digitalWrite(Buzzer, LOW);
delay(1000);
}
float temperature;
String prepareJsonData(float temperature, float humidity, float waterTempSensorA_C, float waterTempSensorB_C, float lux, float flowRate) {
DynamicJsonDocument doc(1024);
doc["temperature"] = temperature;
doc["humidity"] = humidity;
doc["waterTempSensorA"] = waterTempSensorA_C;
doc["waterTempSensorB"] = waterTempSensorB_C;
doc["lux"] = lux;
doc["flowRate"] = flowRate;
String jsonData;
serializeJson(doc, jsonData);
return jsonData;
}
void loop() {
Blynk.run();
client.loop();
// Check if it's time to read sensors
if (millis() - lastReadTime >= readInterval) {
lastReadTime = millis();
// Read temperature and humidity from DHT11
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
// Read water temperature sensors A and B
waterTempSensorA.requestTemperatures();
float waterTempSensorA_C = waterTempSensorA.getTempCByIndex(0);
waterTempSensorB.requestTemperatures();
float waterTempSensorB_C = waterTempSensorB.getTempCByIndex(0);
// Read lux from light meter
float lux = lightMeter.readLightLevel();
// Read water flow rate
float flowRate = waterFlowSensor.getCurrentFlowrate();
// Prepare JSON data
String jsonData = prepareJsonData(temperature, humidity, waterTempSensorA_C, waterTempSensorB_C, lux, flowRate);
Serial.println("JSON data: " + jsonData);
// Publish JSON data to the MQTT topic
client.publish("hydroponics/data", jsonData.c_str());
}
}