ชื่อโปรเจกต์: Pet Care IoT
เกี่ยวกับโปรเจกต์นี้
ในโปรเจกต์นี้ พี่จะพาน้องๆ ไปดูวิธีทำระบบดูแลสัตว์เลี้ยงสุดล้ำ ซึ่งเราจะได้เรียนรู้เรื่องพวกนี้กัน:
- การสื่อสารแบบ I2C ระหว่าง Microcontroller สองตัว
- การคุยกันผ่าน Websocket ระหว่าง Microcontroller กับ ASP.NET Core Server
- การเชื่อมต่อระหว่าง App Android กับ Asp.Net Core Server
พี่จัดเซ็ตอุปกรณ์มาให้เลือก 2 แบบ จัดไปตามความถนัด:
- ESP8266 และ [Arduino](https://s.shopee.co.th/7fUgFAWSki) Uno (อันนี้คือเซ็ตแรกที่พี่ทำ)
- ESP-01 และ Arduino Nano (อันนี้คือเซ็ตที่สอง เล็กพริกขี้หนู)
โปรเจกต์นี้ประกอบไปด้วยเทคโนโลยีเทพๆ ตามนี้เลย:
- การเชื่อมต่อแบบ Master/Slave I2C connection ระหว่าง ESP8266 กับ Arduino Uno (หรือ ESP-01 กับ Arduino Nano)
- Xamarin.Android สำหรับทำแอป Android
- Asp.Net Core Web API ร่วมกับ WebSocket ทำหน้าที่เป็น Middleware คอยรับส่งข้อมูลแบบ Real-time
ทางเลือกที่ 1
- เริ่มแรก พี่ลองทำแบบให้ Android คุยกับ ESP8266 ตรงๆ เลย
ข้อดี: ทำง่ายจัดๆ
ข้อเสีย: ใช้ได้แค่ตอนอยู่ที่บ้าน (Local Network เท่านั้น)
ทางเลือกที่ 2
- พี่เลยลองเปลี่ยนไปใช้ ThingSpeak ช่วย แต่บอกตรงๆ ว่าไม่ค่อยโดน เพราะมันติดเรื่องดีเลย์ 15 วินาทีของ ThingSpeak พี่อยากได้แบบกดปุ๊บติดปั๊บ ไม่ได้แค่อยากเก็บ Data อย่างเดียว
ข้อดี: สั่งงานได้ทั่วโลก
ข้อเสีย: ไม่ Real-time มันต้องรอ 15 วินาทีถึงจะอัปเดตข้อมูล พี่เซ็งตรงนี้แหละ
ทางเลือกที่ 3 (ตัวจบ)
ในเมื่อไม่ถูกใจ พี่เลยเขียน Server "Middleware" ขึ้นมาเองเลย เพื่อเชื่อม Android กับ Arduino เข้าด้วยกัน โดยใช้ ASP.NET Core ร่วมกับ Websocket แล้วเอาไป Deploy ไว้บน SmarterASP แบบฟรีๆ
ข้อดี: Real-time ของจริง สั่งงานได้จากทุกที่ทั่วโลก
ข้อเสีย: ตอนนี้ยังไม่เจอว่ะน้อง หล่อเท่เลยงานนี้
ฟีเจอร์เด็ด
โปรเจกต์นี้ทำอะไรได้บ้าง:
- ให้อาหารสัตว์เลี้ยง (Pet feeder)
- ระบบรดน้ำ/เติมน้ำ (Watering system)
- เปิด-ปิดไฟ (Light)
- สื่อสารแบบ Real-Time
- มีรายงานผลและสถิติให้ดูด้วย
เครื่องให้อาหาร (Feeder)
ไอเดียเครื่องนี้พี่ได้แรงบันดาลใจมาจากคลิปนี้ มันใช้ [Servo](https://s.shopee.co.th/7fUgFAWSki) motor แค่ตัวเดียว ทำง่ายมากน้อง
อุปกรณ์ที่ต้องใช้:
- S90G (Servo)
- กล่องใส่อาหาร (เอาพวกกระบอกมันฝรั่งทอดมาทำก็ได้)
- ฐานวางกล่องอาหารและที่ยึด S90G
- แหล่งจ่ายไฟ 5V - พี่ใช้ Output 5V จาก Module L298N
พยายามเจาะรูให้ใหญ่หน่อยนะน้อง อาหารจะได้ไม่ติดขัด ถึงมันจะดูไม่ได้ซับซ้อนมาก แต่พอมีระบบ Monitor ผ่านแอปแล้ว ก็ถือว่าใช้งานได้ดีเลยทีเดียวแหละ เอาไว้ใช้ขัดตาทัพก่อนที่ Stepper motor จะมาส่ง
โหมดการทำงาน:
- ตอนนี้เน้นกดมือ (Manual) ไปก่อน
NodeMcu จะรับข้อความมา แล้วประมวลผลส่งต่อไปให้ Arduino เพื่อสั่งงานอุปกรณ์
#define SERVO_PIN 3
......
//ใน setup();
servo.attach(SERVO_PIN);
servo.write(4);
ค่า '4' ตรงนี้คือค่าเริ่มต้นนะ
ส่วนตอนให้อาหารใช้ Code นี้ พี่ลองไล่ค่าดูแล้วจนได้จังหวะที่พอดี
servo.write(180);
delay(700);
servo.write(4);
ระบบเติมน้ำ (Watering system)
อุปกรณ์:
- ปั๊มน้ำ 5V DC
- Module L298N motor driver - ต่อเข้ากับแหล่งจ่ายไฟ 12V
- ตู้ปลาเก่าๆ
- [Sensor](https://s.shopee.co.th/7VBG2rX65j) วัดระดับน้ำ (หรือ Soil moisture sensor ก็ได้)
พี่บอกเลยนะ เซนเซอร์ความชื้นในดินไม่ค่อยเวิร์คหรอกน้อง มันพังง่าย (Corrode) แนะนำให้ใช้ Water sensor ของจริง หรือจะทำเองแบบ DIY ก็ได้
โหมดการทำงาน:
- Auto - ปั๊มทำงานเองถ้าน้ำลดต่ำลง และจะหยุดเมื่อน้ำเต็มชาม
- Manual - สั่งเปิดจากแอป Android แต่พอน้ำเต็มมันจะหยุดเองโดยอัตโนมัติ (ห้ามช็อตนะตัวนี้ เซ็ตค่าดีๆ)
- ถ้าจะถ่ายน้ำออกจากถัง ก็แค่ดึง Sensor ออกจากชาม
NodeMcu จะรอรับคำสั่ง แล้วส่งต่อให้ Arduino จัดการเหมือนเดิม
ค่าระดับน้ำจะส่งจาก Arduino ไปยัง NodeMcu ทุกๆ 2 วินาที
ประกาศ Pins ด้านบน:
#define enA 9
#define in1 8
#define in2 7
แล้วเซ็ตเป็น Output ให้หมด พร้อมสั่ง LOW ไว้ก่อน:
pinMode(enA, OUTPUT);
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);
digitalWrite(in1, LOW);
digitalWrite(in2, LOW);
digitalWrite(LIGHT_PIN, LOW);
ตัวอย่าง Code
// อัดความเร็วเต็มสูบ
analogWrite(enA, 255);
// เริ่มการทำงาน
digitalWrite(in1, HIGH);
digitalWrite(in2, LOW);
int sensorLevel = analogRead(A3);
// ปล่อยรันไปจนกว่าน้ำจะเต็ม
while(sensorLevel >= WATER_LEVEL_HIGH)
{
sensorLevel=analogRead(A3);
delay(150);
}
// พอเต็มแล้วก็หยุดสิครับ
digitalWrite(in1, LOW);
digitalWrite(in2, LOW);
ระบบไฟ (Light)
อุปกรณ์:
- [Relay](https://s.shopee.co.th/3fyXTmWPbL) 5V
- หลอดไฟ 220V
สารภาพตามตรง อันนี้ไม่เกี่ยวกับสัตว์เลี้ยงเท่าไหร่หรอก แต่มันช่วยให้ชีวิตพี่สบายขึ้น ไม่ต้องลุกไปปิดไฟก่อนนอนไงล่ะน้อง!
NodeMcu รับเรื่องมา แล้วส่งต่อให้ Arduino สับ Relay ให้ จบๆ ไป
I2C (การเชื่อมต่อแบบ Master/Slave)
I2C คือโปรโตคอลการสื่อสารแบบ Serial หรือจะเรียกว่า TWI (Two-wire interface) ก็ได้ เพราะมันใช้สายแค่ 2 เส้นเอง คือ SDA (Data) และ SCL (Clock)



I2CAddressESPWifi ต้องกำหนดให้ตรงกันทั้งสองฝั่งนะ (ในที่นี้คือเลข 8) เป็นส่วนสำคัญของโปรโตคอลเลย ----> #define I2CAddressESPWifi 8
- Library ที่ใช้: "Wire.h"
ฝั่ง Esp8266
- ในฟังก์ชัน Setup():
Wire.begin(D1, D2); // หรือ Wire.begin(0,2) ถ้าใช้ ESP-01
- การส่งข้อมูลไปหา Arduino
Wire.beginTransmission(I2CAddressESPWifi);
Wire.write("ส่งข้อความอะไรไปก็ได้");
Wire.endTransmission();
ฝั่ง Arduino
- ในฟังก์ชัน Setup():
Wire.begin(I2CAddressESPWifi);
Wire.onReceive(espWifiReceiveEvent);
Wire.onRequest(espWifiRequestEvent);
......
void espWifiReceiveEvent(int count)
{
// ทำอะไรบางอย่างเมื่อได้รับข้อมูล
}
void espWifiRequestEvent(){
Wire.write("ส่งข้อมูลกลับไปให้ ESP");
}
ระบบการสื่อสาร (Communication)

ระบบนี้แบ่งการคุยออกเป็น 3 ส่วน:
1. Client 1 (Android หรือ PC) - ส่งคำสั่งผ่าน Middleware ไปหา ESP8266 และ Arduino
2. Middleware (แอป Asp.Net Core ที่มี Websockets) - เป็นจุดศูนย์กลางคอยกระจายข้อความแบบ Real-time และเก็บประวัติลง Database
3. Client 2 (ESP8266 และ Arduino) - คอยรับคำสั่งจาก Client 1 และส่งค่าจาก Sensor กลับไปเป็นระยะๆ
ตัว Client 1 และ Server เขียนด้วย C# ส่วน Client 2 ก็คือ Code ของ Arduino และ ESP8266 นั่นแหละ
Sketch ของ ESP8266 พี่ใช้ Library ตัวนี้ (WebSockets_Generic) ในนั้นมีตัวอย่างการใช้ดีมาก ลองไปแกะดู
ในโปรเจกต์นี้ พี่สร้าง Object WebSocket ขึ้นมาโดยระบุ IP และ Port ของ Server ใน Code Arduino เราไม่ต้องใส่ "ws://" นำหน้านะ ใส่แค่ Address ไปเลย
ฝั่ง ESP8266
// ตัวแปร Global
WebSocketsClient webSocket;
IPAddress serverIP(192, 168, 0, 1);
สั่งเริ่มทำงาน WebSocket ใน Setup หลังจากต่อ WiFi เสร็จ เราสามารถตั้งค่า Header, ระยะเวลา Reconnect หรือทำ Heartbeat ก็ได้นะ
// ใส่ token ใน header สักหน่อย
webSocket.setExtraHeaders(token.c_str());
// เริ่มลุย!
webSocket.begin(serverIP, 61955, "/");
// จัดการ Event หลัก
webSocket.onEvent(webSocketEvent);
// ถ้าหลุด ให้ลองต่อใหม่ทุก 15 วินาที
webSocket.setReconnectInterval(15000);
// ตั้งค่า Heartbeat (เผื่อไว้)
// Ping server ทุก 60 วินาที
// รอ Pong กลับมาภายใน 10 วินาที
// ถ้า Pong ไม่มา 2 รอบติด ถือว่าเน็ตบิน
webSocket.enableHeartbeat(60000, 10000, 2);
webSocketEvent คือพระเอกที่คอยจัดการเหตุการณ์ต่างๆ ทั้งตอนต่อติด ตอนหลุด หรือตอนที่มีข้อมูลวิ่งเข้ามา
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length){
switch (type){
case WStype_DISCONNECTED:
if (alreadyConnected)
{
Serial.println("หลุดแล้วว่ะน้อง!");
alreadyConnected = false;
}
break;
case WStype_CONNECTED:
{
alreadyConnected = true;
Serial.print("เชื่อมต่อ Websocket สำเร็จ!");
}
break;
case WStype_TEXT:
processPayload((char *) payload);
break;
case WStype_PING:
Serial.printf("[WSc] get ping\
");
break;
case WStype_PONG:
Serial.printf("[WSc] get pong\
");
break;
default:
break;
}
}
สังเกตนะน้อง พี่เอาข้อมูลไปจัดการต่อที่ case WStype_TEXT
โดยแยกประเภทของข้อความตามนี้:
void processPayload(char * payload){
StaticJsonDocument<300> doc;
String jsonObject = String(payload);
auto error = deserializeJson(doc, jsonObject);
if (error) {
Serial.println("ถอดรหัส JSON พลาดว่ะ");
return;
}
int messageType = doc["Type"];
writeToArduino(messageType);
readFromArduino(doc);
}
สองฟังก์ชันนี้จะใช้ Wire.h เพื่อสั่งงาน Arduino และรับผลลัพธ์กลับมา
ฝั่ง Arduino
เป็นโค้ดคุม Motor และ Relay พื้นฐานเลยน้อง แต่เพราะใช้ Wire.h เลยต้องมี Event 2 ตัวคือ Received (รับข้อมูล) และ Request (เมื่อโดนขอข้อมูล)
ใน Received พี่จะตั้ง Flag ไว้ว่าจะเปิด Motor หรือ Relay แล้วค่อยไปเช็ค Flag ใน Loop ถ้าเป็น True ก็สั่งลุย!
void espWifiReceiveEvent(int count){
byte value;
value = Wire.read();
process(value);
}
void process(int messageType){
if(messageType == (int)LIGHT_ON)
{
digitalWrite(LIGHT_PIN, HIGH);
waitingForResponse = true;
}
else if(messageType == (int)LIGHT_OFF)
{
digitalWrite(LIGHT_PIN, LOW);
waitingForResponse = true;
}
else if(messageType == (int)FEEDER_START)
{
servoState = true;
}
else if(messageType == (int)PUMP_START)
{
pumpState = true;
}
else if(messageType == (int)GET_VALUES)
{
requestType = (int)GET_VALUES;
}
}
ส่วน Flag สำหรับ Request จะถูกตั้งไว้เมื่องานเสร็จ พอฝั่ง Master (ESP) ร้องขอข้อมูลมา พี่ก็จะส่งค่ากลับไปตาม Flag พวกนั้น
void espWifiRequestEvent(){
if(waitingForResponse)
{
Wire.write(DONE);
waitingForResponse = false;
}
else if(requestType == (int)GET_VALUES)
{
Wire.write(sensor); // ส่ง 8 บิตล่าง
Wire.write((sensor >> 8)); // ส่ง 8 บิตบน
}
else
{
-1;
}
}
แอป Android และ Web application
ไปดู Code ส่วนของ Android และ Web ได้ที่ส่วน Code เลย พี่เขียน Comment อธิบายไว้ให้แล้ว น้องๆ เอาไปปรับแก้ตามที่ต้องการได้เลยนะ

โปรเจกต์ที่เสร็จสมบูรณ์

รายละเอียดทางเทคนิคเพิ่มเติม
การจัดการสุขภาพสัตว์เลี้ยงจากระยะไกล
Pet Care IoT คือระบบบูรณาการที่ออกแบบมาเพื่อให้แน่ใจว่าสัตว์เลี้ยงของคุณจะอิ่มท้องและอยู่ในสายตาตลอดเวลาแม้ตอนคุณไม่อยู่บ้าน
- ตารางการให้อาหารอัตโนมัติ: ใช้ stepper motor-driven auger ในการจ่ายอาหารแห้งตามน้ำหนักที่แม่นยำ โดย Arduino จะคอยตรวจสอบ "Portion Size" เพื่อให้ตรงตามความต้องการด้านโภชนาการที่ตั้งไว้
- การตรวจสอบสภาพแวดล้อม: ตรวจสอบผ่าน SmarterAsp.net cloud interface โดยระบบจะติดตามอุณหภูมิห้องและระดับน้ำในชาม เพื่อให้มั่นใจว่าสัตว์เลี้ยงของคุณอยู่ในสภาพแวดล้อมที่สบายที่สุด
การโต้ตอบกับเจ้าของ
- Web-Service Dashboard: พัฒนาด้วย Visual Studio 2017 พอร์ทัลเว็บช่วยให้เจ้าของสามารถสั่ง "Manual Treat" (ให้รางวัล) และดู Log แบบ Real-time ได้ว่าสัตว์เลี้ยงกินอาหารครั้งล่าสุดเมื่อไหร่ เพื่อความสบายใจผ่าน Link ที่โฮสต์อยู่บน Cloud อย่างปลอดภัย สู้งานนะน้อง!