โปรเจกต์ Plant Communicator (เครื่องสื่อสารกับต้นไม้)
เคยอยากลองพูดคุยกับต้นไม้ของคุณบ้างไหม?
เคยอยากลองพูดคุยกับต้นไม้ของคุณบ้างไหม?
Note: This tutorial could be outdated, please go ที่นี่ สำหรับเวอร์ชันที่เป็นปัจจุบันมากกว่า
อย่างที่กวีชาวอังกฤษ William Wordsworth เคยกล่าวไว้ว่า:
"จิตใจของคุณคือสวน ความคิดของคุณคือเมล็ดพันธุ์ การเก็บเกี่ยวอาจเป็นได้ทั้งดอกไม้หรือวัชพืช"
การดูแลต้นไม้ให้มีชีวิตรอดอาจเป็นเรื่องท้าทายทีเดียว เพราะพวกมันสื่อสารไม่เก่งเลย
วิธีหนึ่งที่จะทำให้พวกมันมีความสุขคือการพาต้นไม้ติดตัวไปด้วย แต่คุณคงไม่อยากแบกกระบองเพชรยักษ์หรือเฟิร์นไว้ในกระเป๋าเสื้อกันหนาวหรอก แถมต้นไม้ส่วนใหญ่ยังไม่ชอบอากาศหนาวด้วย
หลังจากพยายามสื่อสารกับต้นแมงมุม (Spider Plant) ของเราอยู่นานหลายเดือน เราจึงยอมแพ้และหันมาใช้ส่วนประกอบจาก MKR IoT Bundle เพื่อสร้างอุปกรณ์ที่ใช้ตรวจสอบความเป็นอยู่ของต้นไม้จากระยะไกลแทน
ในบททดลองนี้ คุณจะได้เรียนรู้วิธีปกป้องต้นไม้ของคุณและทำให้แน่ใจว่าพวกมันจะอยู่รอดด้วยการใช้เวทมนตร์ของ Arduino
ด้วยการตรวจสอบความชื้น (moisture), อุณหภูมิ (temperature) และแสงสว่าง (light) คุณจะมั่นใจได้ว่าต้นไม้ของคุณมีความสุข อุปกรณ์นี้สามารถส่งอีเมลและกราฟเป็นประจำทุกวัน พร้อมทั้งแจ้งเตือนคุณเมื่อมันต้องการการดูแล
บทช่วยสอนนี้เป็นส่วนหนึ่งของชุดการทดลองที่จะทำให้คุณคุ้นเคยกับ MKR1000 และ IoT การทดลองทั้งหมดสามารถสร้างขึ้นได้โดยใช้ส่วนประกอบที่มีอยู่ใน MKR IoT Bundle
Zapier เป็นเครื่องมืออัตโนมัติออนไลน์ที่สามารถจัดการ API ของแอปอื่นๆ ให้เราได้อย่างง่ายดาย เป็นเครื่องมือที่ยอดเยี่ยมในการรวมหลายงานเข้าด้วยกัน หรือในกรณีที่แอปที่เราต้องการใช้มี API ที่ซับซ้อนซึ่งไม่สามารถจัดการได้ด้วย Arduino
ในกรณีของเรา เราจะใช้มันเพื่อส่งอีเมลพร้อมข้อมูลที่ได้รับจาก Arduino
ทำตามขั้นตอนง่ายๆ เหล่านี้เพื่อสร้าง Zap ของคุณเอง!




เพื่อให้ดำเนินการต่อได้ เราจำเป็นต้องทดสอบ hook ของเราก่อน โดยคัดลอก URL ที่ได้รับมา จากนั้นเลือกปุ่ม Test and Review ที่ปรากฏขึ้นเมื่อคุณกด Continue เพิ่มพารามิเตอร์เหล่านี้ต่อท้าย URL:
custom_webhook_URL?temperature=0&moisture=0&light=0&warning=0
ตอนนี้เพียงแค่คัดลอกและวาง URL นี้ลงในหน้าเบราว์เซอร์ใหม่
คุณควรเห็นการตอบกลับดังนี้:


ยินดีด้วย! คุณเพิ่งส่ง http request สำเร็จ!
นี่คือสิ่งที่เราจะทำกับ Board Arduino ของเรา แต่แทนที่จะวาง URL นั้นลงในเบราว์เซอร์ เราจะส่งไปยังเซิร์ฟเวอร์ของ Zapier โดยตรง นอกจากนี้เราจะแก้ไขค่าของพารามิเตอร์ที่ตอนนี้ตั้งเป็นศูนย์ด้วยค่าจาก Sensor ของเรา
สำหรับวิธีที่ก้าวหน้าขึ้นในการทดสอบและทำงานกับ API ให้ดูที่ #ProTip ที่ด้านล่างของหน้า
หลังจากที่คุณทดสอบคำขอแล้ว คุณสามารถดำเนินการสร้าง Zap ต่อได้
ดำเนินการต่อในส่วน Edit ด้วย Do This...








ตรวจสอบกล่องจดหมายของคุณเพื่อดูอีเมลที่สร้างจาก Zapier ซึ่งจะส่งมาจากบัญชีที่คุณใช้ในขั้นตอนแรกของการกำหนดค่า Gmail
ในการใช้งานฟังก์ชันทั้งหมด เราจะใช้ไลบรารีต่อไปนี้:
คุณสามารถดาวน์โหลดไลบรารีเหล่านี้ได้จาก Library Manager ตามที่อธิบายไว้ใน คู่มือนี้
ในการใช้ API ของ Zapier อันดับแรกเราต้อง upload certificates ลงใน MKR1000 สิ่งนี้ใช้กับบริการออนไลน์และ API ส่วนใหญ่!
อัปโหลดตัวอย่าง Firmware Updater จากไลบรารี WiFi101 และเพิ่ม hooks.zapier.com ลงใน domains
> examples > WiFi101 > FirmwareUpdater
หากคุณใช้ Arduino Web Editor ฟีเจอร์นี้ยังไม่รองรับ และคุณต้องทำผ่าน Arduino Desktop Application



ตอนนี้เราพร้อมที่จะส่ง HTTP request จาก Board Arduino แล้ว
สำหรับตอนนี้ เราจะตั้งค่าพารามิเตอร์เป็นค่าสมมติ ซึ่งภายหลังจะถูกแทนที่ด้วยค่าจริงจาก Sensor
float temperature = 22;
int moisture = 150;
int light = 40;
String warning = "This is a warning message";
warning.replace(" ", "%20");
โปรดทราบว่า String จะต้องถูกเข้ารหัส (encoded) เนื่องจากไม่สามารถส่งช่องว่างใน HTTP request ได้ ช่องว่างทั้งหมดจะถูกแทนที่ด้วยรหัสที่เทียบเท่าคือ %20
หลังจากตั้งค่าพารามิเตอร์แล้ว เราจะเรียกฟังก์ชัน send_email() ซึ่งจะแปลงค่าทั้งหมดเป็น String และ จะสร้าง URL แบบเดียวกับที่เราใช้ก่อนหน้านี้ เพื่อส่งไปยังเซิร์ฟเวอร์ของ Zapier
กรอกข้อมูล WiFi ของคุณและส่วนของ URL ที่คุณได้รับจาก Zapier ลงใน sketch นี้แล้วอัปโหลด
#include <WiFi101.h>
#include<WiFiSSLClient.h>
const char* ssid = SECRET_SSID; // your network SSID (name)
const char* password = SECRET_PSWD; // your network password
String httpsRequest = SECRET_REQUEST; // your Zapier URL
const char* host = "hooks.zapier.com";
WiFiSSLClient client;
void setup() {
Serial.begin(9600);
while (!Serial);
delay(2000);
Serial.print("Connecting Wifi: ");
Serial.println(ssid);
while (WiFi.begin(ssid, password) != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.println("");
Serial.println("WiFi connected");
}
void loop() {
float temperature = 22;
int moisture = 150;
int light = 40;
String warning = "This is a warning message";
warning.replace(" ", "%20");
send_email(temperature, moisture, light, warning );
delay(20000);
}
void send_email(float temperature, int moisture, int light, String warning) {
// convert values to String
String _temperature = String(temperature);
String _moisture = String(moisture);
String _light = String(light);
String _warning = warning;
if (client.connect(host, 443)) {
client.println("POST " + httpsRequest + "?temperature=" + _temperature + "&moisture=" + _moisture + "&light=" + _light + "&warning=" + _warning + " HTTP/1.1");
client.println("Host: " + String(host));
client.println("Connection: close");
client.println();
delay(1000);
while (client.available()) { // Print on the console the answer of the server
char c = client.read();
Serial.write(c);
}
client.stop(); // Disconnect from the server
}
else {
Serial.println("Failed to connect to client");
}
}
มันจะส่งอีเมลไปยังที่อยู่ที่คุณเลือกทุกๆ 20 วินาที
ระวังเรื่องจำนวนคำขอ Zapier ให้คุณส่งได้ฟรีเพียง 100 ครั้งต่อเดือนเท่านั้น
เราสามารถใช้ Real Time Clock ของ MKR1000 เพื่อส่งอีเมลทุกวันในเวลาที่กำหนด
sketch นี้จะตั้งเวลาและวันที่เป็น 16:00 ของวันที่ 4 ธันวาคม 2017 แล้วจึงตั้งปลุกทุกวันเวลา 16:01
โปรดทราบว่าเนื่องจากการปลุกเชื่อมต่อกับฟังก์ชัน interrupt เราจึงไม่สามารถใส่คำสั่ง delay ได้ แต่เราสามารถใช้ Variable ประเภท boolean เพื่อกระตุ้นการทำงานใน loop()
#include <RTCZero.h>
RTCZero rtc; // create RTC object
/* Change these values to set the current initial time */
const byte seconds = 0;
const byte minutes = 0;
const byte hours = 16;
/* Change these values to set the current initial date */
const byte day = 4;
const byte month = 12;
const byte year = 17;
bool email_already_sent = false;
void setup() {
Serial.begin(9600);
while (!Serial);
delay(2000);
rtc.begin(); // initialize RTC 24H format
rtc.setTime(hours, minutes, seconds);
rtc.setDate(day, month, year);
rtc.setAlarmTime(16, 1, 0); // Set the time for the Arduino to send the email
rtc.enableAlarm(rtc.MATCH_HHMMSS);
rtc.attachInterrupt(alarmMatch);
}
void loop() {
if (!email_already_sent) {
// send_email();
email_already_sent = true;
}
}
void alarmMatch() { // triggered when the alarm goes on
Serial.println("Alarm Match!");
email_already_sent = false;
}
สายไฟสองเส้นที่วางอยู่ในกระถางดินทำหน้าที่เป็นตัวต้านทานที่แปรค่าได้ ซึ่งความต้านทานจะเปลี่ยนไปตามความชื้นในดิน
ตัวต้านทานที่แปรค่าได้นี้จะถูกเชื่อมต่อในรูปแบบวงจรแบ่งแรงดัน (voltage divider) และ Arduino จะเก็บค่าแรงดันไฟฟ้าที่เป็นสัดส่วนกับความต้านทานระหว่างสายไฟ 2 เส้นนั้น
หมายความว่า ยิ่งดินมีความชื้นมากเท่าไหร่ แรงดันไฟฟ้าที่วัดได้จาก Arduino ก็จะยิ่งน้อยลงเท่านั้น
โดยการใช้ ตัวต้านทานขนาด 1 Mega Ohm และสายไฟสองเส้น เราสามารถสร้าง DIY soil moisture sensor ของเราเองได้!

เมื่ออัปโหลด sketch ต่อไปนี้ คุณสามารถเริ่มอ่านค่าจาก Sensor ได้ เราขอแนะนำให้คุณ เริ่มทดสอบในดินแห้งก่อน และจดค่าที่อ่านได้ไว้
ค่านั้นจะถูกใช้เพื่อตั้งค่าเกณฑ์ (threshold) เพื่อให้ Arduino รู้ว่าเมื่อใดที่ต้นไม้ของคุณต้องการน้ำ และส่ง อีเมลฉุกเฉิน มาหาคุณ
int moisturePin = A2;
// Set this threshold accordingly to the resistance you used
// The easiest way to calibrate this value is to test the sensor in both dry and wet soil
int threshold = 800;
void setup() {
Serial.begin(9600);
while (!Serial);
delay(2000);
}
void loop() {
Serial.println(get_average_moisture());
delay(5000);
}
int get_average_moisture() { // make an average of 10 values to be more accurate
int tempValue = 0; // variable to temporarily store moisture value
for (int a = 0; a < 10; a++) {
tempValue += analogRead(moisturePin);
delay(100);
}
return tempValue / 10;
}
ดูแผนผังด้านล่างเพื่อต่อวงจร Sensor ทั้งสองตัว เราจะใช้ฟังก์ชันสองตัวนี้ในการอ่านค่าจาก Sensor:
float get_temperature(){
int reading = analogRead(A1);
float voltage = reading * 3.3;
voltage /= 1024.0;
// Print temperature in Celsius
float temperatureC = (voltage - 0.5) * 100 ; //converting from 10 mv per degree with 500 mV offset
// Convert to Fahrenheit
float temperatureF = (temperatureC * 9.0 / 5.0) + 32.0;
return temperatureC;
}
int get_light(){
int light_value=analogRead(A0);
return light_value;
}
โปรดทราบว่าคุณสามารถใช้หน่วย Fahrenheit ได้โดยการสั่ง return temperatureF แทน temperatureC
สำหรับคนที่ชอบควบคุมทุกอย่าง นี่คือคำแนะนำในการพล็อตกราฟข้อมูลทั้งหมดที่เก็บรวบรวมได้ให้เป็นกราฟที่สวยงามแบบนี้:

เราจะใช้แพลตฟอร์ม ThingSpeak เพื่อพล็อตกราฟ ทำตามขั้นตอนเหล่านี้เพื่อเริ่มต้น



ดาวน์โหลดไลบรารี ThingSpeak และมาเริ่มต้นกันเลย sketch ด้านล่างนี้จะอัปโหลดค่าจาก Sensor ขึ้นระบบ cloud ทุกๆ นาที เพียงกรอกข้อมูล WiFi และ API keys ของ channel ของคุณแล้วอัปโหลด
#include <WiFi101.h>
#include<WiFiSSLClient.h>
#include "ThingSpeak.h"
const char* ssid = SECRET_SSID; // your network SSID (name)
const char* password = SECRET_PSWD; // your network password
WiFiClient ThingSpeakClient;
unsigned long myChannelNumber = 356392;
const char * myWriteAPIKey = SECRET_WRITE_API;
int lightPin = A0; //the analog pin the light sensor is connected to
int tempPin = A1; //the analog pin the TMP36's Vout (sense) pin is connected to
int moisturePin = A2;
void setup() {
Serial.begin(9600);
while (!Serial);
delay(2000);
Serial.print("Connecting Wifi: ");
Serial.println(ssid);
while (WiFi.begin(ssid, password) != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.println("");
Serial.println("WiFi connected");
ThingSpeak.begin(ThingSpeakClient);
}
void loop() {
ThingSpeak.setField(1, get_light());
ThingSpeak.setField(2, get_temperature());
ThingSpeak.setField(3, get_average_moisture());
ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
Serial.println("message sent to cloud");
delay(60000); // send values every 1 minute
}
float get_temperature() {
int reading = analogRead(tempPin);
float voltage = reading * 3.3;
voltage /= 1024.0;
// Print temperature in Celsius
float temperatureC = (voltage - 0.5) * 100 ; //converting from 10 mv per degree with 500 mV offset
// Convert to Fahrenheit
float temperatureF = (temperatureC * 9.0 / 5.0) + 32.0;
return temperatureC;
}
int get_average_moisture() { // make an average of 10 values to be more accurate
int tempValue = 0; // variable to temporarily store moisture value
for (int a = 0; a < 10; a++) {
tempValue += analogRead(moisturePin);
delay(10);
}
return tempValue / 10;
}
int get_light() {
int light_value = analogRead(A0);
return light_value;
}
ใน sketch แบบ Pro ตัวเต็มด้านล่าง คุณจะเห็นวิธีเชื่อมต่อการอัปโหลดนี้เข้ากับ RTC alarm ที่จะถูกกระตุ้นทุกๆ นาที
น่าเสียดายที่ Gmail ไม่อนุญาตให้เราฝัง กราฟ และ iframes ลงในเนื้อหาอีเมล แต่เราสามารถส่งลิงก์ผ่านอีเมลในรูปแบบปุ่มที่สวยงามได้ ดูคำแนะนำด้านล่าง
เราเลือกใช้ ThingSpeak แต่ยังมีทางเลือกอื่นอีกมากมาย! เช่น ลองดู Dweet.io และ freeboard.io เป็นต้น
Zapier อนุญาตให้เรา ฝังโค้ด html และ css ในเนื้อหา ของอีเมล เราสามารถใช้สิ่งนั้นเพื่อส่งอีเมลที่ตกแต่งอย่างสวยงามแบบนี้:

เพื่อให้ได้ผลลัพธ์นี้ เพียงแค่เปลี่ยน body type เป็น html บนหน้าจอ Zapier และเพิ่ม HTML และ CSS ของคุณเอง


คัดลอกและวาง template นี้:
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
.container{
margin-left: 10%;
margin-right: 10%;
background-color: #ECF1F1;
min-height: 100%;
padding-top: 5%;
padding-bottom: 10%;
font-family: monospace;
letter-spacing: 2px;
}
.title{
text-align: center;
color: #0CA1A6;
font-size: 1.5em;
padding-top: 0.2vh;
}
.subtitle{
text-align: center;
color: #0CA1A6;
font-size: 1.1em;
padding-bottom: 4%;
padding-left: 4%;
padding-right: 4%;
}
.data{
padding-bottom: 2%;
padding-top: 2%;
padding-left: 5%;
margin-left: 15%;
margin-right: 15%;
background-color: #F7F9F9;
text-align: left;
color: #4E5B61;
font-size: 1em;
font-weight: bold;
}
.bttn{
padding-bottom: 3%;
padding-top: 3%;
margin-left: 25%;
margin-right: 25%;
margin-top: 10%;
background-color: #00979D;
text-align: center;
color: #F7F9F9;
font-size: 1.4em;
}
.disclaimer{
text-align:center;
color:#DA5B4A;
font-size: 1.1em;
font-weight: bold;
margin-top: 10%;
}
.bttn:hover{
background-color: #008184;
}
a{
text-decoration: none;
}
</style>
</head>
<body>
<div class="container">
<h2 class="title">HELLO !</h2>
<h4 class="subtitle">Here's your daily update about your garden ☘</h4>
<div class="data"> ♨ Temperature: {{querystring__temperature}} C </div>
<div id="humidity" class="data"> ☔ Moisture: {{_querystring__moisture}}</div>
<div class="data"> ☀ Light: {{querystring__light}}</div>
<div class="disclaimer">{{querystring__warning}}</div>
<a href="your_link_to_thingSpeak">
<div class="bttn">SEE THE GRAPH</div>
</a>
</div>
</body>
</html>
การทำงานกับ HTTP request อาจเป็นเรื่องยาก โชคดีที่มีเครื่องมือมากมายที่ช่วยเราสร้าง URL ที่เราต้องการได้
Postman เป็นตัวอย่างที่ยอดเยี่ยม:

เพียงวาง URL เริ่มต้นที่ได้รับจาก Zapier เพิ่มพารามิเตอร์แล้วกดส่ง มันจะแสดงผลการตอบกลับจากเซิร์ฟเวอร์และประกอบ URL ให้กับคุณ
สนับสนุนเพื่อรับ Source Code หรือแอปพลิเคชันสำหรับโปรเจกต์นี้