วันอังคารที่ 7 มิถุนายน พ.ศ. 2559


   

สวัสดีครับก่อนที่เราจะมาทำความรู้จักกับ Project IoT เริ่มด้วยผมเป็นนักศึกษาฝึกงานมาจากมหาวิทยาลัยเทคโนโลยีราชมงคลตะวันออก วิทยาเขตจักรพงษภูวนารถ  คณะบริหารธุรกิจเเละเทคโนโลยีสารสนเทศฯ ซึ่งมาฝึกงานด้าน Hardware เนื่องจากบริษัทที่มาฝึกงานเป็นบริษัทเกี่ยวกับ เทคโนโลยี ดังนั้นพี่ที่ดูแลในส่วนของ Engineer จึงได้มอบหมายโปรเจ็คโดยมอบ Sensor ชื่อว่า Soil moisture เซนเซอร์สำหรับวัดปริมาณน้ำในดิน ให้มาประยุกต์ใช้กับ NETPIE ที่เป็น Platform as a Service มีหน้าที่ บริการการเชื่อมต่อข้อมูลและแลกเปลี่ยนข้อมูลระหว่างอุปกรณ์ต่างๆ

เครื่องรดน้ำต้นไม้อัติโนมัติ

    การรดน้ำต้นไม้อาจเป็นปัญหาใหญ่สำหรับคนปลูกต้นไม้ แต่ไม่ค่อยมีเวลาว่างดังนั้นเครื่องรดน้ำต้นไม้อัตโนมัติจึงจำเป็นกับเหล่าบรรดาผู้รักต้นไม้ เราขอแนะนำในส่วนของเครื่องรดน้ำต้นไม้อัจฉริยะสามารถสั่งรดน้ำต้นไม้ด้วยระบบ IoT ที่ทันสมัย รวดเร็ว ทันใจ สะดวกสบาย หมดห่วงเรื่องระยะทาง ลดเวลา ในการรดน้ำต้นไม้โดยสั่งการผ่าน browser หรือจะ แปลง จาก HTML5 ไป เป็นแอพ Android เพื่อเพิ่มความเป็นส่วนตัว เเละสะดวกมากขึ้น






















อุปกรณ์ที่ใช้

1. Board NodeMCU v2

 2. Soil moisture sensor
 3. Water flow sensor
4. Relay
5. Solenoid Valve


  •     Node MCU : บอร์ดตัวนี้เป็นบอร์ดที่รวมเอา ESP8266 (ESP-12) + USB to Serial +NodeMCU firmware เข้าไว้ด้วยกัน ทำให้การใช้งานง่ายมากขึ้น ไม่ต้องมีอุปกรณ์ต่อพ่วงเยอะ แถมมี GPIO เพิ่มเป็น 10 พอร์ท เพียงพอต่อการใช้งาน สำหรับ NodeMCU devkit ที่ได้มาเป็นบอร์ดเปล่าๆ ใช้ AT Command ในการสั่งงาน
  •     Soil moisture sensor : เซนเซอร์นี้คือเซนเซอร์สำหรับวัดปริมาณน้ำในดินแบบง่าย ซึ่งสามารถนำมาวัดความชื้นที่อยู่ภายในดินได้ โดยให้ค่าoutput เป็นแบบดิจิตอล สามารถปรับค่าได้ด้วยตัวต้านทานปรับค่าได้ที่อยู่บนบอร์ดสามารถนำเซนเซอร์ตัวนี้มาทำเป็นระบบรดน้ำต้นไม้อัตโนมัติได้อย่างง่ายดายหรือหากต้องการค่าที่แม่นยำมากขึ้นสามารถอ่านค่าเป็นแบบ analog
  •     Relay : อุปกรณ์อิเล็กทรอนิกส์ที่ทำหน้าที่เป็นสวิตซ์ตัด-ต่อวงจรโดยใช้แม่เหล็กไฟฟ้า[1] และการที่จะให้มันทำงานก็ต้องจ่ายไฟให้มันตามที่กำหนดเพราะเมื่อจ่ายไฟให้กับตัวรีเลย์ มันจะทำให้หน้าสัมผัสติดกันกลายเป็นวงจรปิด และตรงข้ามทันทีที่ไม่ได้จ่ายไฟให้มัน มันก็จะกลายเป็นวงจรเปิด ไฟที่เราใช้ป้อนให้กับตัวรีเลย์ก็จะเป็นไฟที่มาจาก เพาเวอร์ฯ ของเครื่องเรา ดังนั้นทันทีที่เปิดเครื่อง ก็จะทำให้รีเลย์ทำงาน
  •    Water flow sensor  ออกแบบมาสำหรับตรวจจับอัตราการไหลของน้ำโดยเฉพาะ ในตัวของมันประกอบด้วย โรเตอร์หรือแกนหมุนสำหรับรับน้ำที่มีแม่เหล็กชิ้นเล็กๆ ติดอยู่ และตัวตรวจจับฮอลล์เอฟเฟ็กต์ ซึ่งบรรจุอยู่ภายในตัวถังพลาสติกซึ่งผลิตจากไนล่อนและไฟเบอร์ที่มีข้อต่อสำหรับทางน้ำเข้าและทางน้ำออก เมื่อน้ำไหลเข้ามาในตัวตรวจจับ แกนหมุนที่อยู่ภายในจะหมุน ทำให้แม่เหล็กที่ติดอยู่กับใบพัดของแกนหมุนนั้นเกิดการเคลื่อนที่ผ่าตัวตรวจจับฮอลล์เอฟเฟ็กต์ ทำให้เกิดสัญญาณพัลส์ซึ่งจะมีอัตราตามความเร็วของกระแสน้ำที่ไหลเข้ามาในตัวตรวจจับ
  •    Solenoid Valve  อุปกรณ์ทางอิเล็คโตร แมคเนติค ที่ใช้ควบคุมปริมาตรของของไหลที่ไหลผ่านท่อ โดยการเปิดหรือปิดที่รู orifices ของตัววาล์วโซลีนอยด์วาล์วเป็นการรวมกันของ 2 รูปแบบการทำงาน คือ  SOLENOID  จะเป็นตัวทำหน้าที่สร้างสนามแม่เหล็กและเหนี่ยวนำให้ plunger เคลื่อนที่ขึ้นลง  VALVE  ตัววาล์วจะมีรู orifice ที่มี disc คอยปิดและเปิดให้ของไหลไหลผ่านวาล์ว

ส่วนของการต่อวงจร


















Soil Moisture Sensor

Vcc=3V

A0=A0

GND=GND















Water flow sensor

Vcc=5V

D0=D2 //ขึ้นอยู่กับ code ที่เรียกใช้

GND=GND


NodeMCU pin definition

























ขั้นตอนการแสดงผลและการทำงาน


    










    


    เริ่มจาก Soil Moisture Sensor ทำการวัดค่าความชื้นในดินแล้วทำการส่งค่าความชื้นไปยัง Node MCU เพื่อให้ Node MCU ทำการส่งค่าขึ้นไปยัง Cloud และทำการแสดงผลบนน่าเว็บบราวเซอร์ นอกจากนั้นยังสามารถสั่งเปิด/ปิด น้ำจากเว็บบราวเซอร์ได้

















ส่วนของ Code Arduino
#include <AuthClient.h>
#include <MicroGear.h>
#include <MQTTClient.h>
#include <SHA1.h>
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <EEPROM.h>
#include <MicroGear.h>
#include <string.h>
const char* ssid = "WIFI_SSID";
const char* password = "WIFI_KEY";
#define APPID "APPID"
#define GEARKEY "APPKEY"
#define GEARSECRET "APPSECRET"
#define SCOPE ""
WiFiClient client;
AuthClient *authclient;
int timer = 0;
MicroGear microgear(client);
byte sensorInterrupt = 5; // 0 = digital pin 2
byte sensorPin = D1;
int sensorValue ;
// The hall-effect flow sensor outputs approximately 4.5 pulses per second per
// litre/minute of flow.
float calibrationFactor = 4.5;
volatile byte pulseCount;
float flowRate;
unsigned int flowMilliLitres;
unsigned long totalMilliLitres;
unsigned long oldTime;
char Mode[128]="A" ;
char Order[128]="F" ;
int X=30 ;
int Y=500 ;
void onMsghandler(char *topic, uint8_t* msg, unsigned int msglen) {
Serial.print("Incoming message --> ");
digitalWrite(2,1);
delay(100);
digitalWrite(2,0);
delay(100);
digitalWrite(2,1);
delay(100);
digitalWrite(2,0);
delay(100);
//สัญญาณไฟ
msg[msglen] = '\0';
if (msg[0] == 'S'){
msg += 1;
X=my_str2int((char *) msg);
Serial.println(X);
}
if (msg[0] == 'Q'){
msg += 1;
Y=my_str2int((char *) msg);
Serial.println(Y);
}
if (strcmp((char *)msg,"A")==0||strcmp((char *)msg,"M")==0){
strcpy(Mode,(char *)msg);}
else{strcpy(Order,(char *)msg);
}
Serial.println((char *)msg);
}
int my_str2int(const char *s)
{
int res = 0;
while (*s) {
res *= 10;
res += *s++ - '0';
}
return res;
}
void onFoundgear(char *attribute, uint8_t* msg, unsigned int msglen) {
Serial.print("Found new member --> ");
for (int i=0; i<msglen; i++)
Serial.print((char)msg[i]);
Serial.println();
}
void onLostgear(char *attribute, uint8_t* msg, unsigned int msglen) {
Serial.print("Lost member --> ");
for (int i=0; i<msglen; i++)
Serial.print((char)msg[i]);
Serial.println();
}
void onConnected(char *attribute, uint8_t* msg, unsigned int msglen) {
Serial.println("Connected to NETPIE...");
microgear.setName("Autowater_Arduino");
}
void pulseCounter()
{
// Increment the pulse counter
pulseCount++;
}
void setup() {
/* Event listener */
microgear.on(MESSAGE,onMsghandler);
microgear.on(PRESENT,onFoundgear);
microgear.on(ABSENT,onLostgear);
microgear.on(CONNECTED,onConnected);
Serial.begin(115200);
pinMode(16,OUTPUT);
pinMode(4, OUTPUT);
pinMode(0, OUTPUT);
pinMode(2, OUTPUT);
pinMode(sensorPin, INPUT);
digitalWrite(sensorPin, HIGH);
Serial.println("Starting...");
if (WiFi.begin(ssid, password)) {
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
//uncomment the line below if you want to reset token -->
//microgear.resetToken();
microgear.init(GEARKEY,GEARSECRET,SCOPE);
microgear.connect(APPID);
}
pulseCount = 0;
flowRate = 0.0;
flowMilliLitres = 0;
totalMilliLitres = 0;
oldTime = 0;
sensorValue = analogRead(A0);
attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
}
void loop() {
sensorValue = analogRead(A0);
int sensorValue2 = (100-(sensorValue)*100.0/1024.0);
if (microgear.connected()) {
Serial.println("connected");
microgear.loop();
Serial.println("Publish...");
if (strcmp(Mode,"A")==0){
Serial.print("Analog: ");
Serial.println(sensorValue);
Serial.print("Moisture of Soil: ");
Serial.print(sensorValue2);
Serial.println(" %");
if (sensorValue2<X)
{
digitalWrite(16,LOW);
digitalWrite(4,1);
digitalWrite(0,0);
Serial.println("Status: On\t");
microgear.chat("Autowater_HTML5","Status= ON");
}
else
{
digitalWrite(16,HIGH);
digitalWrite(4,0);
digitalWrite(0,1);
Serial.println("Status: Off\t");
microgear.chat("Autowater_HTML5","Status= OFF");
}
if( totalMilliLitres >=Y)
{
digitalWrite(16,HIGH);
digitalWrite(4,0);
digitalWrite(0,1);
Serial.println("Status: Off\t");
microgear.chat("Autowater_HTML5","Status= OFF");
totalMilliLitres=0;
delay(20000);
}
if((millis() - oldTime) > 1000)
{
detachInterrupt(sensorInterrupt);
flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
oldTime = millis();
flowMilliLitres = (flowRate / 60) * 1000;
totalMilliLitres += flowMilliLitres;
unsigned int frac;
// Determine the fractional part. The 10 multiplier gives us 1 decimal place.
frac = (flowRate - int(flowRate)) * 10;
// Print the number of litres flowed in this second
Serial.print("Current Liquid Flowing: "); // Output separator
Serial.print(flowMilliLitres);
Serial.println("mL/Sec");
// Print the cumulative total of litres flowed since starting
Serial.print("Output Liquid Quantity: "); // Output separator
Serial.print(totalMilliLitres);
Serial.println("mL");
Serial.println("");
// Reset the pulse counter so we can start incrementing again
pulseCount = 0;
// Enable the interrupt again now that we've finished sending output
attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
}
delay(1000);}
else {
if (strcmp(Order,"N")==0){
digitalWrite(16,LOW);
digitalWrite(4,1);
digitalWrite(0,0);
Serial.println("Status: On\t");
microgear.chat("Autowater_HTML5","Status= ON"); }
else{
digitalWrite(16,HIGH);
digitalWrite(4,0);
digitalWrite(0,1);
Serial.println("Status: Off\t");
microgear.chat("Autowater_HTML5","Status= OFF");
}
unsigned int frac;
// Determine the fractional part. The 10 multiplier gives us 1 decimal place.
frac = (flowRate - int(flowRate)) * 10;detachInterrupt(sensorInterrupt);
flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
oldTime = millis();
flowMilliLitres = (flowRate / 60) * 1000;
pulseCount = 0;
attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
totalMilliLitres += flowMilliLitres;
char msg[128];
char msg1[128];
char msg2[128];
sprintf(msg, "%d,", (int)flowMilliLitres);
sprintf(msg1, "%d,", (int)totalMilliLitres);
sprintf(msg2, "%d", (int)sensorValue2);
strcat(msg,msg1);
strcat(msg,msg2);
microgear.chat("Autowater_HTML5", msg);
microgear.chat("Autowater_HTML5", "Connected");
delay(1000);}
}
else {
Serial.println("connection lost, reconnect...");
if (timer >= 5000) {
microgear.connect(APPID);
timer = 0;
}
else timer += 100;
}
}






















ส่วนของ Code HTML5



<script src="../microgear.js"></script>
<script>
const APPKEY = "APPKEY";
const APPSECRET = "APPSECRET";
const APPID = "APPID";
var microgear = Microgear.create({
gearkey: APPKEY,
gearsecret: APPSECRET
});
microgear.on('message',function(topic,data)
{
if
(data=="Status= ON"||data=="Status= OFF"){
document.getElementById("data4").innerHTML = data;
}else if
(data=="Connected"){
document.getElementById("data").innerHTML = data;
}else{
var split_msg = data.split(",");
var a = parseInt(split_msg[0]);
document.getElementById("data1").innerHTML = "Flowing: "+a+" mL/Sec";
var split_msg = data.split(",");
var b = parseInt(split_msg[1]);
document.getElementById("data2").innerHTML = "Quantity: "+b+" mL" ;
var c = parseInt(split_msg[2]);;
document.getElementById("data3").innerHTML = "Humidity: "+c+ " %";
}
});
microgear.on('connected', function() {
microgear.setname('Autowater_HTML5');
document.getElementById("data").innerHTML = "Now I am connected with netpie...";
});
microgear.on('present', function(event) {
console.log(event);
});
microgear.on('absent', function(event) {
console.log(event);
});
microgear.resettoken();
microgear.connect(APPID);
</script>
<html>
<meta charset="utf-8">
<body background="black.jpg">
<center><font color="#FFFAFA"> <div id="data">_____</div>
<font color="Gold"> <div id="data1">_____</div></font>
<font color="Cyan"> <div id="data2">_____</div></font>
<font color="Green"> <div id="data3">_____</div></font>
<font color="red"> <div id="data4">_____</div></font>
<br><input type="button" value="Auto mode" onclick="Auto()"style="background-color:#00BFFF">
<input type="button" value="Manual mode" onclick="Manual()"style="background-color:#00BFFF">
<br><br><input type="button" value="ON" onclick="ON()" id="on" style="background-color:#00FF00">
<input type="button" value="OFF" onclick="OFF()" id="off" style="background-color:#FF4500">
<div id="AA">
<font color="#00FF00">Moisture of Soil:(%)<br></font>
<input maxlength=2 type="text" name="moisture" id="moisture" onchange="moisture()"style="background-color:#FFE4E1"onKeyUp="if(isNaN(this.value)){ alert('กรุณาใส่ตัวเลขเท่านั้น!!!'); this.value='';}">
<br>
<font color="#FF4500">Water Quantity:(mL)<br></font>
<input maxlength=4 type="text" name="quantity" id="quantity" onchange="quantity()"style="background-color:#FFE4E1"onKeyUp="if(isNaN(this.value)){ alert('กรุณาใส่ตัวเลขเท่านั้น!!!'); this.value='';}">
<br><br>
</div>
</body>
</html>
<script>
function Manual(){
document.getElementById('AA').style.visibility = 'hidden';
document.getElementById('on').style.visibility = 'visible';
document.getElementById('off').style.visibility = 'visible';
microgear.chat("Autowater_Arduino","M");
}
function Auto(){
document.getElementById('AA').style.visibility = 'visible';
document.getElementById('on').style.visibility = 'hidden';
document.getElementById('off').style.visibility = 'hidden';
microgear.chat("Autowater_Arduino","A");
}
function ON(){
microgear.chat("Autowater_Arduino","N");
}function OFF(){
microgear.chat("Autowater_Arduino","F");
}
function moisture(){
alert("Done");
microgear.chat("Autowater_Arduino","S"+document.getElementById('moisture').value);
}
function quantity(){
alert("Done");
microgear.chat("Autowater_Arduino","Q"+document.getElementById('quantity').value);
}
document.getElementById('on').style.visibility = 'hidden';
document.getElementById('off').style.visibility = 'hidden';
document.getElementById('AA').style.visibility = 'hidden';
</script >
Result