
ปัญหาหนึ่งที่ผู้เริ่มต้นพัฒนา 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 ในหนังสือ "คู่มือฝึกอบรมเน็ตพายไอโอที" ซึ่งต่อไปจะเรียกสั้นๆ ว่า คู่มือ

ย้อนกลับไปอธิบายวิธีการใช้ตัวแปรคำสั่งโดยสังเขป ยกตัวอย่าง 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 ซึ่งจะได้กล่าวถึงต่อไป

ฮาร์ดแวร์ที่ใช้ทดลอง
การทดลองในบทความนี้ต้องการเพียง LED 3 ตัวแทน Lamp, Valve, Fertilizer ต่อกับขา D5, D6, D7 ตามลำดับ ผู้อ่านสามารถต่อวงจรบนบอร์ดทดลอง ใช้ผลิตภัณฑ์ IoT Activity ของบริษัท inex หรือในที่นี้จะใช้บอร์ด IGR (Indoor Greenhouse Regulator) ที่ออกแบบโดยผู้เขียนสำหรับการฝึกอบรมดังในรูปที่ 3 LED ทั้งหมดติดตั้งบนบอร์ดอยู่แล้ว ส่วนเซนเซอร์ DHT11 และ BH1750 จะต่อไว้ด้วยเพื่อการแสดงผลบน NETPIE แต่ไม่มีความสำคัญสำหรับบทความนี้ เพราะจะสนใจเพียงการควบคุมโดย sliders และ toggle widget เท่านั้น

แก้ไข NETPIE Freeboard
การทดลองในบทความนี้จะเริ่มแก้ไขในส่วน NETPIE Freeboard ที่เป็นด้านส่งคำสั่ง เพราะเป็นผู้กำหนดชื่อ topic ใน LAB 5.5 ของคู่มือ เราได้พัฒนา NETPIE Freeboard ไว้โดยสมบูรณ์ ลักษณะดังในรูปที่ 4 สามารถใช้ Freeboard เดิมนี้ในบทความ เพียงแต่แก้ไขคำสั่งใน sliders และ toggle เท่านั้น

เริ่มจาก 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 ตามลำดับ

ต่อมาเลือกการตั้งค่า slider widget สำหรับ LAMP จะปรากฏหน้าต่างดังรูปที่ 6 ฟิลด์ที่ต้องการแก้ไขคือ ONSTOP ACTION โดยคำสั่งจะทำงานเพียงครั้งเดียวหลังผู้ใช้หยุดเลื่อน slider (หากใส่ช่อง ONSLIDE ACTION คำสั่งจะถูกส่งไปหลายๆ ครั้งระหว่างเลื่อนซึ่งเปลืองแบนด์วิดท์โดยไม่จำเป็น) คำสั่งที่ใช้เป็นดังนี้
microgear["FBmcpds"].publish("/igsliders/lamp",value)
โดยจะเป็นตัวกำหนดชื่อ topic สำหรับ slider widget นี้คือ "/igsliders/lamp" และค่าที่ส่งไปคือตัวแปร value ซึ่งก็คือค่าที่สอดคล้องกับตำแหน่งของ slider ตัวนี้นั่นเอง

การตั้งค่าสำหรับ 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

เมื่อทราบค่าสตริงที่รับมาในส่วนของ 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)


วีดีโอแสดงการทดสอบ
สรุป
ในบทความนี้เราได้ศึกษาวิธีการควบคุมอุปกรณ์จาก NETPIE widgets หลายตัวโดยวิธีการกำหนด topic ที่แตกต่างกันสำหรับ widget แต่ละตัว วิธีการนี้มีจุดเด่นตรงช่วยลดภาระในการเขียนโปรแกรมเพื่อจัดการสตริง เนื่องจากชื่อ topic จะถูกแยกโดยฟังก์ชัน onMsghandler() ให้อัตโนมัติ ส่วนวิธีการเดิมที่เพิ่มสตริงคำสั่งเข้าไปในข้อความจะต้องเขียนโค้ดส่วนจัดการสตริงเพิ่มขึ้น แต่มีข้อดีคือสามารถกำหนดคำสั่งที่ผู้ใช้สามารถส่งผ่านพอร์ตอนุกรมและ NETPIE ได้โดยใช้ชื่อเดียวกัน ทำให้ควบคุมได้ทั้งจากหน้างานและระยะไกล
โปรแกรมที่ใช้ในตัวอย่าง : NETPIEfbmcp.zip
No comments:
Post a Comment