โปรเจกต์ เริ่มต้นใช้งาน Agriculture IoT (ThingSpeak + Matlab)
โปรเจกต์นี้จะทำการวัดค่า soil moisture, humidity และ temperature จากนั้นจะส่ง data ไปยัง ThingSpeak ผ่านทาง ESP8266
โปรเจกต์นี้จะทำการวัดค่า soil moisture, humidity และ temperature จากนั้นจะส่ง data ไปยัง ThingSpeak ผ่านทาง ESP8266
โปรเจกต์ต่อไปนี้ใช้ Soil Moisture Sensor, DHT11 Temperature Sensor และ ESP8266 เพื่อเก็บค่าอุณหภูมิ, ความชื้น และค่าความชื้นในดิน แล้วส่งข้อมูลเหล่านั้นไปยัง ThingSpeak บทความนี้จะช่วยให้คุณเรียนรู้พื้นฐานการใช้งาน ESP8266 และการส่งข้อมูลจาก Sensor ไปยังเว็บไซต์ผ่าน API อย่าง ThingSpeak

DHT11 Humidity & Temperature Sensor Module เป็น Module สำหรับวัดอุณหภูมิและความชื้นแบบดิจิทัลพื้นฐานราคาประหยัด โดยใช้ capacitive humidity sensor และ thermistor ในการวัดอากาศโดยรอบ และส่งเอาต์พุตเป็นสัญญาณดิจิทัลผ่าน Data Pin (ไม่จำเป็นต้องใช้ช่องสัญญาณ Analog Input)

Soil moisture Sensor Module มีความไวต่อความชื้นโดยรอบสูง โดยทั่วไปจะใช้เพื่อตรวจจับปริมาณความชื้นในดิน เมื่อความชื้นในดินน้อยกว่าค่า Threshold ที่ตั้งไว้ พอร์ต DO จะส่งเอาต์พุตสถานะ High และเมื่อความชื้นในดินเกินค่า Threshold ที่ตั้งไว้ พอร์ต D0 จะส่งเอาต์พุตสถานะ Low; เอาต์พุตดิจิทัล D0 ของบอร์ดขนาดเล็กสามารถเชื่อมต่อโดยตรงกับ Microcontroller เพื่อให้ Microcontroller ตรวจจับสถานะ High และ Low และตรวจสอบความชื้นในดินได้; เอาต์พุตดิจิทัล DO ยังสามารถขับ Relay Module หรือ Buzzer Module ได้โดยตรงเพื่อทำเป็นอุปกรณ์แจ้งเตือนความชื้นในดิน; นอกจากนี้ยังมีเอาต์พุต Analog AO สำหรับเชื่อมต่อกับ AD Module ผ่าน AD converter เพื่อให้ได้ค่าความชื้นในดินที่แม่นยำยิ่งขึ้น
ในการส่งข้อมูลผ่านอินเทอร์เน็ต อันดับแรกเราต้องเชื่อมต่อ ESP8266 กับเครือข่าย WiFi แล้วจึงเขียนโปรแกรมเพื่อให้มันเก็บค่าและส่งไปยัง ThingSpeak API
คำอธิบายสำหรับ Code มีดังนี้:
ขั้นแรกคุณต้องดาวน์โหลด Library สำหรับ ESP8266 และ ThingSpeak โดยคุณสามารถหาได้ที่นี่:
ThingSpeak library: https://github.com/mathworks/thingspeak-arduino
สำหรับการดาวน์โหลด Library ของ ESP8266 ให้ทำตามขั้นตอนดังนี้:


ในการใช้งาน ESP8266 ขั้นแรกให้กำหนดค่าวงจรตามภาพ และอย่าลืม ถอด Microcontroller ออกจากบอร์ด Arduino UNO ก่อนที่จะดำเนินการต่อ

ตอนนี้ เราต้องตั้งค่า ESP8266 ให้อยู่ในโหมด Programming โดยทำตามขั้นตอนดังนี้:
คุณอาจเห็นไฟ LED สีน้ำเงินกะพริบบน ESP8266 หากคุณทำตามขั้นตอนนี้ถูกต้อง เมื่อเสร็จสิ้นขั้นตอนเหล่านี้แล้ว เราก็สามารถไปสู่การอัปโหลดโปรแกรมจริงได้
ข้อมูลสรุปคร่าวๆ ของโปรแกรม:
#include "ThingSpeak.h"
#include <ESP8266WiFi.h>
//------- WI-FI details ----------//
char ssid[] = " "; //SSID here
char pass[] = " "; // Passowrd here
//--------------------------------//
//----------- Channel details ----------------//
unsigned long Channel_ID = ; // Your Channel ID
const char * myWriteAPIKey = " "; //Your write API key
//-------------------------------------------//
const int Field_Number_1 = 1;
const int Field_Number_2 = 2;
const int Field_Number_3 = 3;
String value = "";
int value_1 = 0, value_2 = 0, value_3 = 0;
int x, y, z;
WiFiClient client;
เริ่มแรกเราจะทำการรวม Library และกำหนด Variable ที่จำเป็น ในส่วนของ ssid และ pass ให้ใส่ข้อมูล WiFi ของคุณ (ชื่อและรหัสผ่าน) ตามลำดับ พร้อมทั้งระบุ Channel ID และ Write API Key หากคุณต้องการรู้วิธีการตั้งค่า ThingSpeak สามารถดูได้จากไซต์นี้: Thingspeak set up and basics - Robo India || Tutorials || Learn Arduino || Robotics . เนื่องจากในโปรเจกต์นี้เราจะมี 3 Field (ความชื้นอากาศ, อุณหภูมิ, ความชื้นในดิน) เราจึงใช้ 3 Variable สำหรับหมายเลข Field และ 3 Variable สำหรับค่าต่างๆ
void setup()
{
Serial.begin(115200);
WiFi.mode(WIFI_STA);
ThingSpeak.begin(client);
internet();
}
ในส่วน setup เราจะตั้งค่า Baud Rate เป็น 115200 และเริ่มต้นโหมด WiFi และ ThingSpeak Client
void internet()
{
if (WiFi.status() != WL_CONNECTED)
{
while (WiFi.status() != WL_CONNECTED)
{
WiFi.begin(ssid, pass);
delay(5000);
}
}
}
void upload()
{
ThingSpeak.writeField(Channel_ID, Field_Number_1, value_1, myWriteAPIKey);
delay(15000);
ThingSpeak.writeField(Channel_ID, Field_Number_2, value_2, myWriteAPIKey);
delay(15000);
ThingSpeak.writeField(Channel_ID, Field_Number_3, value_3, myWriteAPIKey);
delay(15000);
value = "";
}
ฟังก์ชัน internet และ upload ถูกกำหนดขึ้นเพื่อให้ ESP8266 เชื่อมต่อกับ WiFi และอัปโหลดข้อมูลที่ได้รับไปยัง ThingSpeak
และนี่คือส่วนสำคัญ:
void loop()
{
internet();
if (Serial.available() > 0)
{
delay(100);
while (Serial.available() > 0)
{
value = Serial.readString();
if (value[0] == '*')
{
if (value[7] == '#')
{
value_1 = ((value[1] - 0x30) * 10 + (value[2] - 0x30));
value_2 = ((value[3] - 0x30) * 10 + (value[4] - 0x30));
value_3 = ((value[5] - 0x30) * 10 + (value[6] - 0x30));
}
}
}
}
upload();
}
ในการส่งข้อมูล เราต้องจัดเรียงข้อมูลให้อยู่ในรูปแบบ Stream ที่ต้องการก่อน จากนั้นจึงเพิ่มสัญลักษณ์เริ่มต้นและสิ้นสุด ซึ่งอธิบายได้ด้วยตัวอย่างนี้:
สมมติว่า ณ เวลาหนึ่ง ค่าอุณหภูมิ, ความชื้น และความชื้นในดินคือ 30C, 71%, และ 62% ตามลำดับ แต่ละค่าเหล่านี้จะมีค่าสูงสุดเป็นเลขจำนวนเต็ม 2 หลัก หากเขียนค่าเหล่านี้ต่อกันตามลำดับจะได้เป็น 30-71-62 หรือในโปรแกรมเราจะเห็นเป็น String '307162' ด้วยวิธีนี้เราจะส่งค่า Sensor ไปยัง Serial Port ซึ่งภายหลังจะถูกแยกโดยโปรแกรมใน ESP8266 อย่างไรก็ตาม เราต้องกำหนดสัญลักษณ์เริ่มต้นและสิ้นสุดเพื่อแยกชุดข้อมูลแต่ละชุด โดยใช้สัญลักษณ์เริ่มต้นเป็น '*' (asterisk) และสัญลักษณ์สิ้นสุดเป็น '#'(hash)
ดังนั้น เราจึงประกาศ Variable ประเภท String ที่ว่างเปล่าไว้ คุณจะเห็นในโปรแกรม Arduino ว่าเมื่อเราต้องการเขียนข้อมูลลงใน Variable นี้ เราจะส่งสัญลักษณ์เริ่มต้นไปยัง Serial Port ก่อน ตามด้วย Stream ข้อมูล และปิดท้ายด้วยสัญลักษณ์สิ้นสุด
ในโปรแกรม ค่าเหล่านี้จะถูกแยกออกง่ายๆ โดยใช้ลำดับดัชนี (indices)
value_1 เก็บค่าอุณหภูมิ, value_2 เก็บค่าความชื้น และ value_3 เก็บค่าความชื้นในดิน
หมายเหตุ: คุณไม่สามารถส่งค่าทศนิยมได้ ซึ่งเข้าใจได้ตามวิธีการที่เราใช้ในการส่งข้อมูล
ตอนนี้ หากคุณตั้งค่า ESP8266 ในโหมด Programming ตามที่อธิบายไว้แล้ว คุณก็พร้อมที่จะอัปโหลด Code ลงใน ESP8266 อีกครั้ง ต้องแน่ใจว่า การเชื่อมต่อ ทั้งหมด ถูกต้อง และ ห้าม เชื่อมต่อ Pin ใดๆ ของ ESP8266 กับ แรงดันไฟ 5V เด็ดขาด มิฉะนั้น คุณ จะทำ IC ไหม้ นอกจากนี้ อย่าลืม ถอด MICROCONTROLLER ออกจาก บอร์ด Arduino ก่อน อัปโหลด Code และต้องแน่ใจว่า คุณได้เลือก Board เป็น 'GENERIC ESP8266 module'
เมื่อคุณทำตามขั้นตอนเหล่านี้เสร็จแล้ว คุณสามารถกดปุ่มอัปโหลดได้
หลังจากที่คุณเขียนโปรแกรมให้ ESP8266 เสร็จเรียบร้อยแล้ว เราจะมาอัปโหลดโปรแกรมฝั่ง Arduino กัน ตรวจสอบให้แน่ใจว่าคุณได้ถอดการเชื่อมต่อ ESP8266 ออกแล้วก่อนดำเนินการต่อ และ เปลี่ยน Board ให้เป็น 'Arduino UNO'.
Sensor ที่ใช้ในวงจรนี้ต้องการหนึ่ง Analog Pin และหนึ่ง Digital Pin โดย DHT11 จะถูกอ่านค่าผ่าน Digital Pin ซึ่งถูกตั้งค่าไว้ในโปรแกรมเป็น Pin 5 และ Pin ของ Soil Moisture Sensor ถูกตั้งไว้ที่ Pin A0
และตามที่กล่าวไว้ก่อนหน้านี้ เราไม่สามารถใช้เลขทศนิยมได้ ซึ่งกลายเป็นปัญหาในการส่งค่าอุณหภูมิและความชื้น ดังนั้นเราจึงใช้ฟังก์ชัน round() จาก Library 'math.h' เพื่อแก้ปัญหานี้ ฟังก์ชันนี้จะประมาณค่าตัวเลขทศนิยมให้เป็นเลขจำนวนเต็มที่ใกล้เคียงที่สุด
การทำงานของโปรแกรมอธิบายคร่าวๆ ได้ดังนี้:
DHT11
ในการใช้งาน DHT11 เราจำเป็นต้องติดตั้ง Library ของมันก่อน: https://drive.google.com/open?id=1aWuF115pMaZbySQS2CIHBxJiPSM1ezhE
ตอนนี้ในการอ่านค่า เราจะใช้ฟังก์ชัน dht.humidity และ dht.temperature ซึ่งจะให้ค่าเป็นทศนิยม ในการส่งข้อมูลนี้เราจะปัดเศษโดยใช้ round(DHT.humidity) และ round(DHT.temperature)
mySerial.print('*'); // Starting char
mySerial.print(round(DHT.temperature)); //2 digit data
mySerial.print(round(DHT.humidity)); //2 digit data
คุณสามารถดูตัวอย่างโปรแกรม DHT11 เพื่อให้เข้าใจ Code ได้ดียิ่งขึ้น
นี่คือการเชื่อมต่อสำหรับ DHT11:

หมายเหตุ: ในที่นี้ Data Pin เชื่อมต่อกับ Pin 2 คุณสามารถเชื่อมต่อกับ Pin ที่ต้องการได้โดยการเปลี่ยนค่า Pin ในโปรแกรมตัวอย่าง
Soil Moisture
ค่าของ Soil Moisture Sensor จะถูกอ่านผ่าน Analog Pin ขั้นแรกคุณต้องรู้ก่อนว่าค่า Analog Output สูงสุดของ Sensor เมื่อใช้งานในดินที่ "มีความชื้น" คือเท่าใด เพียงแค่เชื่อมต่อวงจรตามที่แสดงที่นี่ และอัปโหลด Code ต่อไปนี้ (สังเกตผลที่ Serial Plotter)
void setup() {
// put your setup code here, to run once:
Serial.begin(9600); delay(2000);
}
void loop() {
// put your main code here, to run repeatedly:
Serial.print("Start");
Serial.println(analogRead(A0));
}

จากนั้นให้นำ Sensor เสียบลงในดินและดูค่าสูงสุดที่ทำได้ ค่านี้จะแทนความชื้น 100 เปอร์เซ็นต์ ในกรณีของผมอยู่ที่ 550 และเพื่อให้ได้ค่าเปอร์เซ็นต์เป็นจำนวนเต็ม เราจะใช้ฟังก์ชัน map() โดยค่า Analog ที่อ่านได้จะถูกเก็บไว้ใน Variable op_value:
op_value = map(op_value, 550, 0, 0, 100);
การเขียนแบบนี้หมายความว่า 550 คือ 100 เปอร์เซ็นต์ และ 0 คือ 0 เปอร์เซ็นต์
นี่คือหน้าตาของ Loop Statement ในตอนนี้
ack = 0;
int chk = DHT.read11(DHTxxPIN);
switch (chk)
{
case DHTLIB_ERROR_CONNECT:
ack = 1;
break;
}
if (ack == 0)
{
Serial.print("Temperature(*C) = ");
Serial.println(DHT.temperature);
Serial.print("Humidity(%) = ");
Serial.println(DHT.humidity);
op_value = analogRead(A0);
op_value = map(op_value,550,0,0,100);
Serial.print("Moisture(%): ");
Serial.print(op_value);
Serial.print("%");
Serial.println("\
------------------------- \
");
//------Sending Data to ESP8266--------//
mySerial.print('*'); // Starting char
mySerial.print(round(DHT.temperature)); //2 digit data
mySerial.print(round(DHT.humidity)); //2 digit data
mySerial.print(op_value); //2 digit data
mySerial.println('#'); // Ending char
//------------------------------------//
delay(2000);
}
if (ack == 1)
{
Serial.print("NO DATA");
Serial.print("\
\
");
delay(2000);
}
เราใช้ Variable ack เพื่อตรวจสอบว่า DHT เชื่อมต่อได้ถูกต้องหรือไม่ หมายเหตุ: ไม่จำเป็นต้องใช้ฟังก์ชัน round() สำหรับค่าความชื้นในดิน เนื่องจากมันเป็นเลขจำนวนเต็ม 2 หลักอยู่แล้ว
เชื่อมต่อวงจรแบบเดียวกับที่แสดงในแต่ละส่วน ตรวจสอบให้แน่ใจว่า GPIO0 และ RST ของ ESP8266 ไม่ได้ต่อลง Ground ในขณะที่คุณอัปโหลด Code ของ Arduino
นี่คือลักษณะการเชื่อมต่อสุดท้ายที่ควรจะเป็น:
DHT11
Datapin-->pin5
Vcc------->5V
GND------>GND
SoilmoistureSensor
A0-------->A0
Vcc-------->5V
GND------->GND
ESP8266
3.3V------->3.3V
EN--------->3.3V
GND------>GND
Rx--------->pin10
Tx--------->pin11
RST------->disconnected
GPIO0----->disconnected
GPIO2------>disconnected
สุดท้ายแล้ววงจรอาจจะมีหน้าตาประมาณนี้:


ข้อมูลชุดแรกที่คุณจะได้รับคือค่าศูนย์ทั้งหมด ซึ่งเป็นการยืนยันว่าการเชื่อมต่อ WiFi และ ThingSpeak ของคุณทำงานได้ถูกต้อง ตอนนี้ อย่าลืมว่าเราได้ ใส่ delay 15 วินาทีก่อนส่งข้อมูลในแต่ละ Field ดังนั้นจะใช้เวลารวม 45 วินาทีในการส่งข้อมูลทั้งหมดไปยัง Field ของตนเอง แผนภูมิข้อมูลอาจจะมีลักษณะดังนี้:
คุณยังสามารถเปรียบเทียบข้อมูลซึ่งกันและกันได้ด้วย Matlab Code ง่ายๆ ในขณะที่ใช้ฟังก์ชัน thingSpeakRead() เราจะใช้ Parameter NumMinutes เพื่อเรียกดูข้อมูลภายในระยะเวลาที่กำหนด ดังนั้นการระบุ 10 หมายถึงการเรียกดูข้อมูลจากเมื่อ 10 นาทีที่แล้ว
นอกจากนี้ เนื่องจากการหน่วงเวลา 15 วินาที จะทำให้มีค่า NaN สองค่าเกิดขึ้นก่อนข้อมูลใหม่ในแต่ละ Field เสมอ ดังนั้นเราจึงใช้ ~isnan() เพื่อลบค่าเหล่านี้ออกจาก Variable
อย่าลืมระบุข้อมูลใน Variable Channel ID และ Read API Key:
readID = ;
readkey = ' ';
hum = thingSpeakRead(readID, 'Field', 2, 'NumPoints', 10, 'ReadKey', readkey);
moist= thingSpeakRead(readID, 'Field', 3, 'NumPoints', 10, 'ReadKey', readkey);
hum = hum(~isnan(hum));
moist = moist(~isnan(moist));
stem(moist(end-10:end),hum(end-10:end)')
xlabel('Moisture(%)')
ylabel('Humidity(%)')
readID = ;
readkey = ' ';
temp = thingSpeakRead(readID, 'Field', 1, 'NumMinutes', 10, 'ReadKey', readkey);
moist= thingSpeakRead(readID, 'Field', 3, 'NumMinutes', 10, 'ReadKey', readkey);
temp = temp(~isnan(temp));
moist = moist(~isnan(moist));
stem(moist(end-10:end),temp(end-10:end)')
xlabel('Moisture (%)');
ylabel('Temperature (C)');
นี่คือข้อผิดพลาดที่อาจเกิดขึ้นได้:
หากคุณพบข้อผิดพลาดนี้ แสดงว่า ESP8266 ไมได้อยู่ในโหมด Programming ในขณะที่คุณอัปโหลด Code ดังนั้นอันดับแรกให้ตรวจสอบว่าการเชื่อมต่อถูกต้องหรือไม่ โดยเฉพาะ การเชื่อมต่อ Pin Ground เข้ากับ GPIO0 และ RST นอกจากนี้ ต้องแน่ใจว่าคุณใช้ Library ของ ESP และ ThingSpeak ตัวเดียวกับในบทความนี้เพื่อเลี่ยงข้อผิดพลาดอื่นๆ

ข้อมูลแรกที่ส่งไปยัง ThingSpeak จะเป็นศูนย์ทั้งหมด ซึ่งแสดงว่าการเชื่อมต่อระหว่าง ESP8266 และ ThingSpeak สำเร็จแล้ว หากคุณได้รับเพียงค่าศูนย์เท่านั้น คุณอาจต้องตรวจสอบว่ามีการส่งข้อมูลจาก Arduino มาหรือไม่ โดยทำดังนี้:
เปิด Serial Monitor ของคุณแล้วพิมพ์ค่าสุ่มในรูปแบบ *XXXXXX# ซึ่งคล้ายกับวิธีที่เราส่งค่า Sensor หากคุณเห็นผลลัพธ์ในแผนภูมิ แสดงว่ามีการส่งข้อมูลผ่าน แต่ค่า Sensor อาจไม่อยู่ในรูปแบบเลขจำนวนเต็มที่ถูกต้อง ลองตรวจสอบดูว่าเลขจำนวนเต็มประเภทใดที่ถูกส่งไปยัง Serial Port และต้องแน่ใจว่าค่าที่ส่งในฟังก์ชัน myserial.print() ถูกปัดเศษด้วยฟังก์ชัน round() หรือวิธีอื่นๆ ตามโปรแกรมของคุณ ข้อกำหนดเพียงอย่างเดียวคือค่าเหล่านั้นต้องเป็นเลขจำนวนเต็ม 2 หลัก
สุดท้าย ในส่วน Matlab Visualization ของ ThingSpeak คุณอาจเห็นข้อผิดพลาดเหล่านี้:


นี่เป็นเพราะ Variable ยังมีค่าไม่เพียงพอที่จะสร้างแผนภูมิ ตามที่ระบุไว้ใน Code โปรแกรมต้องการ 10 ค่าเพื่อสร้างแผนภูมิ และมันจะดึงข้อมูล 10 ค่านี้นมาจาก การทำงานในช่วง 10 นาทีที่ผ่านมา ดังนั้นหากคุณยังใช้งานระบบไม่นานพอ คุณจะมีข้อมูลไม่เพียงพอ คุณสามารถเปลี่ยนระยะเวลาในการพล็อตแผนภูมิได้ตามต้องการ แต่จำไว้ว่าเมื่อเริ่มรันระบบครั้งแรก คุณจะต้องรอประมาณ 10-15 นาทีเพื่อให้มีข้อมูลครบสำหรับพล็อตแผนภูมิ ระยะเวลาสั้นที่สุดที่คุณสามารถตั้งได้คือ 5 นาที
สนับสนุนเพื่อรับ Source Code หรือแอปพลิเคชันสำหรับโปรเจกต์นี้
ประเมิน Project
เอาฟอร์มยาวออกจากท้ายหน้า Project แล้ว เหลือเป็นปุ่มให้กดไปกรอกหน้าเดียว ตัวใหญ่ เว้นบรรทัดเยอะ อ่านง่ายกว่า
รีวิวจากคนใช้งานจริง
ถ้าเคยสั่งงาน เคยอ่านหน้านี้แล้วได้ประโยชน์ หรือมีข้อเสนอแนะ ฝากรีวิวไว้ได้เลย
ยังไม่มีรีวิวบนหน้านี้ ถ้าเคยใช้งานหรือมีข้อเสนอแนะ เขียนเป็นคนแรกได้เลย