ปัญหาหนึ่งที่ผู้เริ่มต้นพัฒนา NETPIE Freeboard ประสบเมื่อเพิ่ม widget สำหรับควบคุมฮาร์ดแวร์จำนวนมากกว่า 1 ตัวขึ้นไป คือต้องการให้อุปกรณ์ทางด้านรับสามารถแยกได้ว่าข้อมูลถูกส่งมาจาก widget ตัวใด เพื่อที่จะตอบสนองต่อคำสั่งนั้นได้อย่างถูกต้อง ทางแก้ที่ผู้เขียนเคยนำเสนอและใช้ได้ดีคือการเพิ่มสตริงส่วนที่เป็นคำสั่งเข้าไปในข้อมูลที่ chat มาจาก widget แต่ละตัว และสร้างฟังก์ชันแปลคำสั่งทางด้านรับ อย่างไรก็ตามสำหรับ IoT ขนาดเล็กที่มี widget ควบคุมเพียง 2-3 ตัว การเขียนฟังก์ชันแปลคำสั่งอาจจะเกินความจำเป็น ดังนั้นในบทความนี้จะนำเสนอทางเลือกอีกวิธีหนึ่ง คือทางด้านส่งใช้ฟังก์ชัน microgear.publish() โดยระบุ topic ที่แตกต่างกัน ทำให้ทางด้านรับสามารถแยกข้อมูลและทำงานตาม topic ที่ตั้งไว้
เพื่อยกตัวอย่างที่เป็นรูปธรรม โจทย์ปัญหาการควบคุมโดย widget หลายตัวในบทความนี้แสดงในรูปที่ 1 คือต้องการปรับความสว่างของหลอดไฟ (Lamp) และอัตราการไหลของวาล์วน้ำ (Valve) โดย slider widgets และปิด/เปิดการให้ปุ๋ยโดย toggle widget ฮาร์ดแวร์ตัวประมวลผลที่ใช้คือ ESP8266 (NodeMCU) โจทย์ตัวอย่างนี้ยกมาจาก LAB 5.3 ในหนังสือ
"คู่มือฝึกอบรมเน็ตพายไอโอที" ซึ่งต่อไปจะเรียกสั้นๆ ว่า คู่มือ
รูปที่ 1 โจทย์ปัญหาการควบคุมโดย Freeboard widget 3 ตัว
ย้อนกลับไปอธิบายวิธีการใช้ตัวแปรคำสั่งโดยสังเขป ยกตัวอย่าง slider widget โดยวิธีการเดิมที่ใช้ คำสั่งที่ส่งให้กับอุปกรณ์คือ
microgear["datasource"].chat("alias","text"+value)
สตริง "text" ที่สอดแทรกเข้าไปในข้อความที่ chat จะไม่ซ้ำกันในแต่ละ widget ช่วยให้อุปกรณ์สามารถแยกได้ว่าส่งมาจาก widget ตัวใด โปรแกรมทางด้านรับจะต้องมีกรรมวิธีการประมวลผลสตริง วิธีการที่ผู้เขียนใช้คือกำหนดอักขระพิเศษเพื่อแยกระหว่างคำสั่งกับค่าจาก slider ตัวอย่างเช่น redled=value คำสั่งคือ redled หรือปรับความสว่างของหลอด LED สีแดง เราสามารถใช้ฟังก์ชันของออปเจ็ค String เพื่อแยกคำสั่งได้โดยง่าย เพื่อความง่ายในการบำรุงรักษาโปรแกรม ส่วนรับและแปลคำสั่งจะเขียนเป็นฟังก์ชัน cmdInt() ซึ่งมีจุดเด่นคือคำสั่งเดียวกันสามารถส่งจาก NETPIE และจากผู้ใช้หน้างานผ่านพอร์ตอนุกรม
ในกรณีที่ผู้ใช้ต้องการควบคุมอุปกรณ์ IoT ผ่านอินเทอร์เน็ตเพียงอย่างเดียวและไม่ต้องการเขียนโปรแกรมแยกสตริงให้ยุ่งยาก วิธีที่สองที่นำเสนอคือกำหนดชื่อ topic ที่แตกต่างกันให้กับข้อความที่ publish มาจาก widget แต่ละตัว ซึ่งทางด้านรับสามารถตรวจสอบชื่อ topic และแยกทำงานตามต้องการได้ ซึ่งเป็นวิธีที่จะสาธิตในบทความนี้
การแยกข้อความโดย topic
วิธีการแยกข้อความจาก widget หลายตัวตาม topic แสดงได้ดังรูปที่ 2 โดยทางผู้ส่งข้อความจะใช้วิธี microgear.publish() แทน microgear.chat() ส่วนทางด้านรับจะต้อง subscribe topic ที่ต้องการรับ สามารถใช้ wild cards # เพื่อลดจำนวนคำสั่งที่ใช้ subscribe ได้ รายละเอียดในส่วนนี้ศึกษาได้จากคู่มือและสไลด์ของ NETPIE การแยกข้อมูลด้านผู้รับจะอาศัยความแตกต่างของ topic ซึ่งจะได้กล่าวถึงต่อไป
รูปที่ 2 การแยกข้อความจาก widget หลายตัวตาม topic
ฮาร์ดแวร์ที่ใช้ทดลอง
การทดลองในบทความนี้ต้องการเพียง LED 3 ตัวแทน Lamp, Valve, Fertilizer ต่อกับขา D5, D6, D7 ตามลำดับ ผู้อ่านสามารถต่อวงจรบนบอร์ดทดลอง ใช้ผลิตภัณฑ์ IoT Activity ของบริษัท inex หรือในที่นี้จะใช้บอร์ด IGR (Indoor Greenhouse Regulator) ที่ออกแบบโดยผู้เขียนสำหรับการฝึกอบรมดังในรูปที่ 3 LED ทั้งหมดติดตั้งบนบอร์ดอยู่แล้ว ส่วนเซนเซอร์ DHT11 และ BH1750 จะต่อไว้ด้วยเพื่อการแสดงผลบน NETPIE แต่ไม่มีความสำคัญสำหรับบทความนี้ เพราะจะสนใจเพียงการควบคุมโดย sliders และ toggle widget เท่านั้น
รูปที่ 3 ด้านบนของบอร์ด IGR แสดง LED 3 ตัวที่ต้องการควบคุม
แก้ไข NETPIE Freeboard
การทดลองในบทความนี้จะเริ่มแก้ไขในส่วน NETPIE Freeboard ที่เป็นด้านส่งคำสั่ง เพราะเป็นผู้กำหนดชื่อ topic ใน LAB 5.5 ของคู่มือ เราได้พัฒนา NETPIE Freeboard ไว้โดยสมบูรณ์ ลักษณะดังในรูปที่ 4 สามารถใช้ Freeboard เดิมนี้ในบทความ เพียงแต่แก้ไขคำสั่งใน sliders และ toggle เท่านั้น
รูปที่ 4 หน้า Freeboard เดิมจาก LAB 5.5
เริ่มจาก toggle widget คลิกเพื่อตั้งค่าจะปรากฏหน้าต่างดังรูปที่ 5 ช่องที่ต้องแก้ไขคือ ONTOGGLEON ACTION ใส่คำสั่ง
microgear["FBmcpds"].publish("/igtoggles/fertilizer","1")
และ ONTOGGLEOFF ACTION ใส่คำสั่ง
microgear["FBmcpds"].publish("/igtoggles/fertilizer","0")
โดย "FBmcpds" คือชื่อ datasource สังเกตว่าชื่อ topic สำหรับ toggle widget ได้ถูกกำหนดโดยคำสั่งทั้งสองนี้เท่ากับ "/igtoggles/fertilizer" และค่าที่ส่งคือ 0 และ 1 เมื่อ toggle อยู่ในสถานะ OFF และ ON ตามลำดับ
รูปที่ 5 หน้าต่างสำหรับตั้งค่า toggle widget
ต่อมาเลือกการตั้งค่า slider widget สำหรับ LAMP จะปรากฏหน้าต่างดังรูปที่ 6 ฟิลด์ที่ต้องการแก้ไขคือ ONSTOP ACTION โดยคำสั่งจะทำงานเพียงครั้งเดียวหลังผู้ใช้หยุดเลื่อน slider (หากใส่ช่อง ONSLIDE ACTION คำสั่งจะถูกส่งไปหลายๆ ครั้งระหว่างเลื่อนซึ่งเปลืองแบนด์วิดท์โดยไม่จำเป็น) คำสั่งที่ใช้เป็นดังนี้
microgear["FBmcpds"].publish("/igsliders/lamp",value)
โดยจะเป็นตัวกำหนดชื่อ topic สำหรับ slider widget นี้คือ "/igsliders/lamp" และค่าที่ส่งไปคือตัวแปร value ซึ่งก็คือค่าที่สอดคล้องกับตำแหน่งของ slider ตัวนี้นั่นเอง
รูปที่ 6 การตั้งค่าในช่อง ONSTOP ACTION ของ slider ปรับค่า LAMP
การตั้งค่าสำหรับ valve slider จะใส่ข้อมูลลงในฟิลด์ ONSTOP ACTION เช่นเดียวกับในรูปที่ 6 เพียงแต่เปลี่ยนชื่อ topic เป็น "/igsliders/valve"
microgear["FBmcpds"].publish("/igsliders/valve",value)
โปรแกรม NodeMCU
ในส่วนโปรแกรมด้าน NodeMCU จะแก้ไขจากโปรแกรมเดิมใน LAB 5.5 ของคู่มือ โปรแกรมที่สมบูรณ์แล้วตั้งชื่อว่า DHT11LIGHT_FB_mcp.ino ที่ดาวน์โหลดได้จากด้านล่างของบทความนี้ แต่เพื่อให้เข้าใจหลักการทำงาน จะอธิบายการแก้ไขโปรแกรมเป็นขั้นตอน สิ่งแรกที่ต้องทำคือ subscribe topic ที่ส่งมาจาก Freeboard โดยเพิ่มคำสั่ง microgear.subscribe() ในฟังก์ชัน onConnected()
void onConnected(char *attribute, uint8_t* msg, unsigned int msglen) {
Serial.println("Connected to NETPIE...");
microgear.setAlias(ALIAS);
microgear.subscribe("/igtoggles/fertilizer");
microgear.subscribe("/igsliders/#");
}
สังเกตว่าเราใช้ wildcard # ช่วยลดจำนวนครั้งของการ subscribe topic จาก slider widgets
อธิบายหลักการรับข้อมูลของไลบรารี microgear โดยย่อคือ ข้อความใดๆ ที่ส่งมาให้กับ NodeMCU จะถูกจัดการโดยฟังก์ชัน onMsghandler() ที่มีนิยามดังนี้
void onMsghandler(char *topic, uint8_t* msg, unsigned int msglen);
จะเห็นว่ามีอาร์กิวเมนต์ topic อยู่ ซึ่งจะเป็นตัวแปรที่เก็บชื่อของ topic ที่ส่งมาให้เราโดยอัตโนมัติ กล่าวได้ว่าเป็นจุดเด่นของวิธีการนี้เพราะช่วยลดภาระการเขียนโปรแกรมเพื่อแยกสตริง ในขั้นต้นเราต้องการทราบว่าชื่อ topic ที่ส่งมาจาก Freeboard เป็นอย่างไร ดังนั้นจึงเพิ่มคำสั่งเพื่อแสดงข้อความออกพอร์ตอนุกรมดังนี้
String topicstring = String(topic);
Serial.print("Topic = ");
Serial.println(topicstring);
คอมไพล์และโหลดโปรแกรมลงบน NodeMCU เปิดหน้าต่าง Serial Monitor และทดลองกด toggle และเลื่อน sliders บน Freeboard จะเห็นการแสดงข้อความบน Serial Monitor ดังรูปที่ 7 โดยจะเห็นว่าชื่อ APPID ในที่นี้คือ myESP8266nov3 ถูกเพิ่มเข้าไปหน้าชื่อ topic ที่ตั้งไว้สำหรับ widget แต่ละตัว ส่วนค่าตัวเลขคือข้อมูลสถานะของ toggle และตำแหน่งของ sliders
รูปที่ 7 ข้อมูลที่ส่งมาจาก NETPIE widgets
เมื่อทราบค่าสตริงที่รับมาในส่วนของ topic ก็จะสามารถเขียนโค้ดเพื่อสั่งให้อุปกรณ์ทำงานตามต้องการได้ ข้อความส่วน topic ที่รับมาถูกคัดลอกใส่ตัวแปรแบบ String เพื่อการจัดการสตริงที่ง่ายขึ้น เช่นเดียวกับข้อมูลส่วนที่เป็นค่าสถานะและตำแหน่งของ widget
ในที่นี้งานที่ต้องการทำมีเพียงควบคุมสถานะและความสว่างของ LED 3 ตัวที่นิยามไว้ใน LAB 5.5 ซึ่งโค้ดมีความยาวไม่มากดังนั้นจึงเขียนทั้งหมดไว้ในฟังก์ชัน onMsghandler() กรณีการทำงานที่ซับซ้อนขึ้นแนะนำให้เขียนเป็นฟังก์ชันแยกต่างหาก
void onMsghandler(char *topic, uint8_t* msg, unsigned int msglen) {
Serial.print("Incoming message --> ");
char *m = (char *)msg; // needed to avoid conversion error
m[msglen] = '\0';
String valuestring = m;
Serial.println(valuestring);
String topicstring = String(topic);
Serial.print("Topic = ");
Serial.println(topicstring);
int value = 0; // value from sliders and toggle
if (topicstring.equalsIgnoreCase("/myESP8266nov3/igsliders/lamp")) {
value = valuestring.toInt();
lampvalue = map(value,0,100,0,1023);
analogWrite(LAMP,lampvalue);
update_freeboard();
}
else if (topicstring.equalsIgnoreCase("/myESP8266nov3/igsliders/valve")) {
value = valuestring.toInt();
valvevalue = map(value,0,100,0,1023);
analogWrite(VALVE,valvevalue);
update_freeboard();
}
else if (topicstring.equalsIgnoreCase("/myESP8266nov3/igtoggles/fertilizer")) {
value = valuestring.toInt();
fertilizer_state = value;
digitalWrite(FERTILIZER,fertilizer_state);
update_freeboard();
}
}
สำหรับการกำหนดค่าให้กับเอาต์พุตและการอัพเดทกลับไปยัง Freeboard widgets จะเหมือนกับใน LAB 5.5 ทุกประการ เมื่อคอมไพล์และโหลดโปรแกรม DHT11LIGHT_FB_mcp.ino ลงบน NodeICU จะพบว่าสามารถทำงานได้เช่นเดียวกับวิธีใช้ฟังก์ชันแปลคำสั่งใน LAB 5.5 (รูปที่ 8,9)
รูปที่ 8 ข้อความที่แสดงบน Serial Monitor ขณะรันโปรแกรม DHT11LIGHT_FB_mcp.ino
รูปที่ 9 การทดสอบโดย NETPIE Mobile App
วีดีโอแสดงการทดสอบ
สรุป
ในบทความนี้เราได้ศึกษาวิธีการควบคุมอุปกรณ์จาก NETPIE widgets หลายตัวโดยวิธีการกำหนด topic ที่แตกต่างกันสำหรับ widget แต่ละตัว วิธีการนี้มีจุดเด่นตรงช่วยลดภาระในการเขียนโปรแกรมเพื่อจัดการสตริง เนื่องจากชื่อ topic จะถูกแยกโดยฟังก์ชัน onMsghandler() ให้อัตโนมัติ ส่วนวิธีการเดิมที่เพิ่มสตริงคำสั่งเข้าไปในข้อความจะต้องเขียนโค้ดส่วนจัดการสตริงเพิ่มขึ้น แต่มีข้อดีคือสามารถกำหนดคำสั่งที่ผู้ใช้สามารถส่งผ่านพอร์ตอนุกรมและ NETPIE ได้โดยใช้ชื่อเดียวกัน ทำให้ควบคุมได้ทั้งจากหน้างานและระยะไกล
โปรแกรมที่ใช้ในตัวอย่าง :
NETPIEfbmcp.zip
No comments:
Post a Comment