c. Webserver được tạo để lựa chọn Wi-Fi
6.2. HƯỚNG PHÁT TRIỂN
Hệ thống giám sát nhiều vườn có thể phát triển cách thêm vườn bằng cách thiết kế thêm tính năng xuất được chương trình gốc sau khi điều chỉnh lại các giá trị mong muốn trên giao diện ứng dụng như cần 2 động cơ bơm và 2 đèn thay vì 1, 4 cảm biến thay vì 2. Ngoài ra chương trình sau khi xuất ra từ ứng dụng, người dùng có thể nạp chương trình mà không cần dây để kết nối đến phần cứng, nạp ở bất cứ đâu khi được kết nối Internet để tăng tính tiện lợi của hệ thống. Nhưng để phát triển được như vậy, phải thiết kế và xây dựng hệ thống trên một nền tảng tự viết như Android hoặc IOS thay vì dùng nền tảng Blynk.
82
TÀI LIỆU THAM KHẢO
Tiếng Việt
[1] Trương Ngọc Anh (2013), “Giáo trình vi xử lý”, Nhà xuất bản ĐHQG
Tp. HCM, 323 trang.
[2] Nguyễn Việt Hùng (2007), “Giáo trình kỹ thuật số”, Nhà xuất bản
ĐHQG Tp. HCM, 192 trang.
[3] Trần Thu Hà (2013), “Giáo trình điện tử cơ bản”, Nhà xuất bản ĐHQG
Tp. HCM, 642 trang.
[4] Nguyễn Thị Lưỡng (2013), “Giáo trình điện tử cơ bản”, Nhà xuất bản
ĐHQG Tp. HCM, 642 trang.
[5] Trương Thị Bích Ngà (2013), “Giáo trình điện tử cơ bản”, Nhà xuất bản
ĐHQG Tp. HCM, 642 trang.
[6] Nguyễn Đình Phú (2013), “Giáo trình vi xử lý”, Nhà xuất bản ĐHQG Tp. HCM, 323 trang.
[7] Hà A Thồi (2007), “Giáo trình kỹ thuật số”, Nhà xuất bản ĐHQG Tp.
HCM, 192 trang.
Tiếng Anh
[8] Brian Benchoff (2014), “The ESP8266 WiFI Module”, Hackaday magazine.
[9] David Kushner (2011), “The Making of Arduino”, IEEE Spectrum magazine.
[10] Ivan Grokhotkov (2017), “ESP8266 Arduino Core Documentation”, Arduino, 79 Pages.
[11] Datasheet DHT11, ESP8266 [12] Datasheet Arduino Wemos D1 [13] Datasheet Soil Moisture Sensor [14] Datasheet ESP8266
83
PHỤ LỤC
/* ESP & Blynk */
#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include "EEPROM.h"
#include <BlynkSimpleEsp8266.h>
#include <Wire.h> // I2C library already built in Arduino IDE
#include <LiquidCrystal_I2C.h> //library via Include Library > Manage
Library >
LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7); WidgetLED PUMP(V0); // Đèn trạng thái bơm
WidgetLED LAMP(V1); // Đèn trạng thái đèn sưởi
ESP8266WebServer server(80);
const char* ssid = "XSwitch";
const char* passphrase = "000000000";
String blynk = "0d66cb94e5984f29ae1e8bbd90c584bd";
String st; String content; int statusCode; #include "DHT.h" /* TIMER */ #include <SimpleTimer.h>
#define DHTPIN D2 // Chân DATA nối với D2
84
// Relay, nút nhấn
#define PUMP_ON_BUTTON D9 //Nút điều khiển bằng tay bơm
#define LAMP_ON_BUTTON D8 //Nút điều khiển đèn bằng tay
#define SENSORS_READ_BUTTON D5 //Nút lấy dữ liệu tức thời
#define PUMP_PIN D6 //Bom
#define LAMP_PIN D7 //Den
#define DHTTYPE DHT11 // DHT 11 /* Thông số cho chế độ tự động */ #define DRY_SOIL 50 #define WET_SOIL 85 #define COLD_TEMP 35 #define HOT_TEMP 40 #define TIME_PUMP_ON 5 #define TIME_LAMP_ON 10 /* TIMER */
#define READ_BUTTONS_TM 1L // Tương ứng với giây
#define READ_SOIL_HUM_TM 10L //Đọc cảm biến ẩm đất
#define READ_AIR_DATA_TM 3L //Đọc DHT
#define DISPLAY_DATA_TM 20L //Gửi dữ liệu lên terminal
#define SEND_UP_DATA_TM 20L //Gửi dữ liệu lên blynk
#define AUTO_CTRL_TM 60L //Chế độ tư động
// Biến lưu các giá trị cảm biến
float humDHT = 0;
float tempDHT = 0;
int soilMoist = 0;
// Biến lưu trạng thái bơm
boolean pumpStatus = 1;
85
// Khởi tạo timer
SimpleTimer timer;
// Khởi tạo cảm biến
DHT dht(DHTPIN, DHTTYPE);
void setup() {
pinMode(PUMP_PIN, OUTPUT);
pinMode(LAMP_PIN, OUTPUT);
pinMode(PUMP_ON_BUTTON, INPUT_PULLUP);
pinMode(LAMP_ON_BUTTON, INPUT);
pinMode(SENSORS_READ_BUTTON, INPUT);
aplyCmd();
// Khởi tạo cổng serial baud 115200
Serial.begin(115200);
Serial.println("Do An Tot Nghiep");
dht.begin(); // Bắt đầu đọc dữ liệu
lcd.begin(16,2); // initializing the LCD 16 x 2
lcd.setBacklightPin(3,POSITIVE); // Enable or Turn On the backlight
lcd.setBacklight(HIGH);
lcd.home();
lcd.print("Nhiet do:");
lcd.setCursor(0, 1); lcd.print("Do am:");
PUMP.off();
LAMP.off();
startTimers();
86
delay(10);
Serial.println("Startup");
// read eeprom for ssid, pass and blynk
Serial.println("Reading EEPROM ssid");
String esid;
for (int i = 0; i < 32; ++i)
{
esid += char(EEPROM.read(i));
}
Serial.print("SSID: ");
Serial.println(esid.c_str());
esid.trim();
Serial.println("Reading EEPROM pass");
String epass = "";
for (int i = 32; i < 96; ++i)
{
epass += char(EEPROM.read(i));
}
Serial.print("PASS: ");
Serial.println(epass.c_str());
epass.trim();
Serial.println("Reading EEPROM blynk");
String eblynk = "";
for (int i = 96; i < 128; ++i)
{
eblynk += char(EEPROM.read(i));
}
Serial.print("BLYNK: ");
Serial.println(eblynk.c_str());
87
if ( esid.length() > 1 )
{
WiFi.begin(esid.c_str(), epass.c_str());
if (testWifi())
{
launchWeb(0);
WiFi.disconnect();
char * auth_ = new char[eblynk.length() + 1];
eblynk.toCharArray(auth_, eblynk.length() + 1);
Blynk.begin(auth_, esid.c_str(), epass.c_str());
EEPROM.end(); return; } } setupAP(); EEPROM.end(); }
bool testWifi(void) {
int c = 0;
Serial.println("Xin vui long doi ket noi WIFI");
while ( c < 20 )
{
if (WiFi.status() == WL_CONNECTED)
{
return true;
}
88
Serial.print(WiFi.status());
c++;
}
Serial.println("");
Serial.println("Thoi gian ket noi cham, Mo AP");
return false;
}
void launchWeb(int webtype) {
Serial.println("");
Serial.println("WiFi ket noi");
Serial.print("Dia chi IP: ");
Serial.println(WiFi.localIP());
Serial.print("SoftAP IP: ");
Serial.println(WiFi.softAPIP());
createWebServer(webtype);
// Start the server
server.begin();
Serial.println("May chu bat dau"); }
void setupAP(void) {
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay(100);
int n = WiFi.scanNetworks();
Serial.println("Tim hoan tat");
if (n == 0)
{
89
}
else
{
Serial.print(n);
Serial.println(" networks found");
for (int i = 0; i < n; ++i)
{
// Print SSID and RSSI for each network found
Serial.print(i + 1);
Serial.print(": ");
Serial.print(WiFi.SSID(i));
Serial.print(" (");
Serial.print(WiFi.RSSI(i));
Serial.print(")");
Serial.println((WiFi.encryptionType(i) == ENC_TYPE_NONE) ? " " : "*"); delay(10); } } Serial.println(""); st = "<ol>"; for (int i = 0; i < n; ++i) {
// Print SSID and RSSI for each network found
st += "<li>";
st += WiFi.SSID(i);
st += " (";
st += WiFi.RSSI(i);
st += ")";
st += (WiFi.encryptionType(i) == ENC_TYPE_NONE) ? " " : "*";
st += "</li>";
}
90
delay(100);
Serial.println("softap");
Serial.println(ssid);
Serial.println(passphrase);
WiFi.softAP(ssid, passphrase, 6);
launchWeb(1);
Serial.println("over"); }
void createWebServer(int webtype) {
if ( webtype == 1 )
{
server.on("/", []()
{
IPAddress ip = WiFi.softAPIP();
String ipStr = String(ip[0]) + '.' + String(ip[1]) + '.'
+ String(ip[2]) + '.' + String(ip[3]);
content = "<!DOCTYPE HTML>\r\n<html><h2>XSwitch</h2>";
//content += ipStr;
//content += "<form method='get' action='setting'><table width='100%' border='1'><tr><td width=\"30%\"><label>Wifi</label></td><td width=\"70%\><input name='ssid' length=32 width='500'></td></tr><tr><td><label>Password</label></td><td><input name='pass' length=64 width='500'></td></tr><tr><td><label>Blynk</label></td><td><input name='blynk' length=32 width='500'></td></tr><tr><td></td><td><input type='submit'></tr></tr></table></form>";
content += "<form method=\"get\" action=\"setting\">";
content += "<div>Wifi</div>";
content += "<div><input name=\"ssid\" size=\"40\"></div>";
91
content += "<div><input name=\"pass\" size=\"40\"></div>";
content += "<div>Blynk</div>";
content += "<div><input name=\"blynk\" size=\"40\"></div>";
content += "<div><input type='submit'></div>";
content += "<p>";
content += st;
content += "</p>";
content += "</html>";
server.send(200, "text/html", content);
});
server.on("/setting", []()
{
String qsid = server.arg("ssid");
String qpass = server.arg("pass");
String qblynk = server.arg("blynk");
if (qsid.length() > 0 && qpass.length() > 0)
{
EEPROM.begin(512);
Serial.println("clearing eeprom");
for (int i = 0; i < 128; ++i)
{
EEPROM.write(i, 0);
}
EEPROM.commit();
Serial.println(qsid);
Serial.println("");
Serial.println(qpass);
Serial.println("");
Serial.println(qblynk);
92
Serial.println("writing eeprom ssid:");
for (int i = 0; i < qsid.length(); ++i)
{
EEPROM.write(i, qsid[i]);
Serial.print("Wrote: ");
Serial.println(qsid[i]);
}
Serial.println("writing eeprom pass:");
for (int i = 0; i < qpass.length(); ++i)
{
EEPROM.write(32 + i, qpass[i]);
Serial.print("Wrote: ");
Serial.println(qpass[i]);
}
Serial.println("writing eeprom blynk:");
for (int i = 0; i < qblynk.length(); ++i)
{
EEPROM.write(96 + i, qblynk[i]);
Serial.print("Wrote: ");
Serial.println(qblynk[i]);
}
EEPROM.commit();
EEPROM.end();
content = "{\"Success\":\"Luu vao he thong. Khoi dong
lai ten wifi moi\"}";
statusCode = 200;
}
else
{
93
statusCode = 404;
Serial.println("Sending 404");
}
server.send(statusCode, "application/json", content);
}); } else if (webtype == 0) { server.on("/", []() {
IPAddress ip = WiFi.localIP();
String ipStr = String(ip[0]) + '.' + String(ip[1]) + '.'
+ String(ip[2]) + '.' + String(ip[3]);
server.send(200, "application/json", "{\"IP\":\"" + ipStr
+ "\"}");
});
server.on("/cleareeprom", []()
{
content = "<!DOCTYPE HTML>\r\n<html>";
content += "<h2>XSwitch</h2><p>Clearing the EEPROM</p></html>";
server.send(200, "text/html", content);
Serial.println("clearing eeprom");
for (int i = 0; i < 128; ++i) { EEPROM.write(i, 0); } }); } } void loop() {
94
timer.run(); // Bắt đầu SimpleTimer
Blynk.run();
server.handleClient(); }
/**************************************************************** * Hàm điều khiển nhận tín hiệu từ blynk
****************************************************************/
BLYNK_WRITE(3) // Điều khiển bơm
{
int i = param.asInt();
if (i == 1) { pumpStatus = !pumpStatus; aplyCmd(); } }
BLYNK_WRITE(4) // Điều khiển đèn
{
int i = param.asInt();
if (i == 1) { lampStatus = !lampStatus; aplyCmd(); } }
void getSoilMoist(void) {
int i = 0;
soilMoist = 0;
95
{
soilMoist += analogRead(SOIL_MOIST_1_PIN); //Đọc giá trị cảm biến độ ẩm đất
delay(50); // Đợi đọc giá trị ADC
}
soilMoist = soilMoist / (i);
soilMoist = map(soilMoist, 1023, 0, 0, 100); //Ít nước:0% ==> Nhiều nước 100%
}
void hienthilcd(void) { delay(1000); lcd.setCursor(10,0); lcd.print(tempDHT); lcd.print(" "); lcd.print("C"); lcd.print(" "); lcd.print(" "); lcd.setCursor(10,1); lcd.print(soilMoist); lcd.print(" %"); lcd.print(" "); lcd.print(" "); }
void getDhtData(void) {
tempDHT = dht.readTemperature();
96
if (isnan(humDHT) || isnan(tempDHT)) // Kiểm tra kết nối lỗi thì thông báo.
{
Serial.println("Failed to read from DHT sensor!");
return;
} }
void printData(void) {
// IN thông tin ra màn hình
Serial.print("Do am: ");
Serial.print(humDHT);
Serial.print(" %\t");
Serial.print("Nhiet do: ");
Serial.print(tempDHT);
Serial.print(" *C\t");
Serial.print(" %\t");
Serial.print("Do am dat: ");
Serial.print(soilMoist);
Serial.println(" %");
}
/**************************************************************** Hàm đọc trạng thái bơm và kiểm tra nút nhấn
(Nút nhấn mặc định là mức "CAO"):
****************************************************************/
void readLocalCmd() {
97 if (!digiValue) { pumpStatus = !pumpStatus; aplyCmd(); }
digiValue = debounce(LAMP_ON_BUTTON);
if (!digiValue)
{
lampStatus = !lampStatus;
aplyCmd();
}
digiValue = debounce(SENSORS_READ_BUTTON);
if (!digiValue) { getSoilMoist(); delay(500); getDhtData(); delay(500); hienthilcd(); printData(); } } /*************************************************** Thực hiện điều khiển các bơm
****************************************************/
void aplyCmd() {
if (pumpStatus == 0)
{
98
digitalWrite(PUMP_PIN, HIGH);
PUMP.on();
}
else {
digitalWrite(PUMP_PIN, LOW);
PUMP.off();
}
if (lampStatus == 0)
{
Blynk.notify("Canh bao ==>> DEN ON");
digitalWrite(LAMP_PIN, HIGH);
LAMP.on();
}
else
{
digitalWrite(LAMP_PIN, LOW);
LAMP.off();
} }
/*************************************************** Hàm kiểm tra trạng thái phím bấm
****************************************************/
boolean debounce(int pin) {
boolean state;
boolean previousState;
const int debounceDelay = 60;
previousState = digitalRead(pin);
99
{
delay(1);
state = digitalRead(pin);
if (state != previousState) { counter = 0; previousState = state; } } return state; } /*************************************************** * Chế độ tự động dựa trên thông số cảm biến
****************************************************/
void autoControlPlantation(void) { if (soilMoist < DRY_SOIL) { turnPumpOn(); } if (tempDHT < COLD_TEMP) { turnLampOn(); } } /*************************************************** * Bật bơm trong thời gian định sẵn
****************************************************/
void turnPumpOn() {
100 aplyCmd(); readLocalCmd(); delay (TIME_PUMP_ON * 1000); pumpStatus = 1; aplyCmd(); readLocalCmd(); } ///***************************************************
//* Bật đèn trong thời gian định sẵn
//****************************************************/ void turnLampOn() { lampStatus = 0; aplyCmd(); readLocalCmd(); delay (TIME_LAMP_ON * 1000); lampStatus = 1; aplyCmd(); readLocalCmd(); } /*************************************************** Khởi động Timers ****************************************************/
void startTimers(void) {
timer.setInterval(READ_BUTTONS_TM * 1000, readLocalCmd);
timer.setInterval(READ_AIR_DATA_TM * 1000, getDhtData);
timer.setInterval(READ_SOIL_HUM_TM * 1000, getSoilMoist);
timer.setInterval(SEND_UP_DATA_TM * 1000, sendUptime);
101
timer.setInterval(DISPLAY_DATA_TM * 1000, printData);
timer.setInterval(20000L, hienthilcd);
}
/*************************************************** * Gửi dữ liệu lên Blynk
**************************************************/
void sendUptime() {
Blynk.virtualWrite(10, tempDHT); //Nhiệt độ với pin V10
Blynk.virtualWrite(11, humDHT); // Độ ẩm với pin V11
Blynk.virtualWrite(12, soilMoist); // Độ ẩm đất với V12