ถ้าถนัดตัวอื่นก็ลองนำเอาเนื้อหาไปทดลองปรับใช้กันนะครับ
ส่วนตัวเห็นว่าเป็น Arduino ง่ายต่อการทำความเข้าใจ
บอร์ดที่ใช้ อันนี้อุดหนุนจากสมาชิกในกลุ่ม ESP8266 Thailand ไม่แน่ใจว่าจะยังมีจำหน่ายอยู่หรือป่าว
บอร์ดที่ใช้นี้เข้าโหมดโปรแกรมด้วยการปลดสายจ่ายไฟ กดปุ่ม FLASH ค้างไว้
จากนั้นเสียบสายจ่ายไฟ สักพักค่อยปล่อยปุ่ม FLASH แล้วก็สั่ง upload
ขาที่ต่อกับ LED ซึ่งในโค๊ดคือขา BUILTIN_LED - 2
ตัวโค๊ดผมได้วางไว้ท้ายบทความครับ
โค๊ดจะใช้งานไลบรารี่อยู่ 2 ตัวคือ ESP8266WiFi และ ArduinoJson
ตัวแรกน่าจะมีอยู่แล้ว ส่วนของ ArduinoJson เข้าเวบหากันได้ครับ
เพื่อให้เข้าใจ ก็เลยขอแยกโค๊ดในส่วนที่สำคัญมาอธิบาย ดังนี้
ส่วนแรกเป็นการเชื่อมต่อบอร์ดกับ WiFi
| const char* ssid = "ชื่อ WiFi router"; const char* password = "รหัสผ่าน"; const char* host = "dweet.io"; |
ตัวแปร password สำหรับเจ้าใช้งาน router
ส่วนของ host ในที่นี้เราเลิอกใช้ Dweet.io ที่ได้ใช้มาตั้งแต่โพสต์ก่อนๆ
สำหรับ Service อื่นๆ สามารถทดลองใช้ดูครับ แต่ก็จะต้องทราบว่าข้อมูลที่ตอบกลับมามีรูปแบบเป็นอย่างไร
การเชื่อมต่อกับ LED
| pinMode(BUILTIN_LED - 2, OUTPUT); |
แต่พบว่าสามารถใช้ขา BUILTIN_LED - 2 ได้
ในส่วนขอโค๊ดกำหนดขานี้ให้เป็นแบบบ output ต่อกับ LED
| WiFi.begin(ssid, password); |
| int count = 0; while(WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); if(++count == 10){ Serial.println(); count = 0; } } |
ให้เปิด Serial monitor จะเห็นเครื่องหมายจุดต่อเนื่องกัน
เมื่อต่อสำเร็จก็จะแสดงหมายเลข IP
ถ้าพบว่าไม่สามารถเชื่อมต่อได้ ให้ตรวจสอบ ssid กับ password ว่าถูกต้องหรือไม่
เมื่อได้หมายเลข IP แล้ว ก็เป็นการจบกระบวนการ setup
ต่อไปเป็นส่วนของ loop ซึ่งจะทำการส่งคำร้อง (request) ไปที่ Dweet.io
และรอการตอบกลับ เมื่อได้ข้อมูลครบถ้วน ก็จะนำไปจัดการแยdข้อมูลที่มาแบบ Json ออก
โดยอาศัยไลบรารี่ ArduinoJson
| WiFiClient client; const int httpPort = 80; if(!client.connect(host, httpPort)){ Serial.println("Connection failed"); return; } |
หรือให้ Node-RED ขอข้อมูลจาก Dweet.io ในโพสต์ก่อนหน้า
ถ้าเชื่อมต่อไม่สำเร็จ ก็จะแสดง Connection failed มาที่ Serial monitor
ตรวจสอบชื่อ host อีกครั้ง
| String url = "/get/latest/dweet/for/Node-RED-Supotsaeea"; Serial.print("Requesting URL: "); Serial.println(url); client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Cache-Control: no-cache\r\n" + "Connection: close\r\n\r\n"); delay(1000); |
ตอนที่เราทดสอบอ่านค่าด้วย browser
ตัวแปร url จะไปประกอบกับส่วนอื่นเพื่อให้ client ส่งการร้องขอไปที่ Dweet.io
มีส่วนหนึ่งที่เพิ่มเติมเข้าไป ส่วนนี้ไม่มีในตัวอย่างของไลบรารี่ ESP8266WiFi
คือ Cache-Control:no-cache
เนื่องจากเมื่อทดลองแล้วพบว่าหลังจากทำการรับค่าไปสักระยะหนึ่ง ค่าที่ส่งกลับมาจะไม่ได้เป็นข้อมูลปัจจุบัน
แต่จะนำเอาค่าเก่าหรือค่าที่อยู่ใน cache ส่งมาให้ ทำให้เมื่อสั่งปิด เปิด LED เหมือนจะไม่ทำงาน
ทั้งๆที่ Dweet.io ก็มีข้อมูลส่งกลับมา
ใครพบปัญหาลักษณะนี้ ก็ลองเพิ่มส่วนนี้เข้าไปในโค๊ดดูครับ
ส่วนของ delay(1000) เช่นกันเป็นส่วนที่เพิ่มเติม เพราะการตอบสนองของโฮสอาจจะไม่ทัน
ทำให้ไม่ได้รับข้อมูล ค่า delay ที่กำหนดอาจจะต้องมากหรือน้อยกว่านี้ ให้ทดลองปรับเปลี่ยนกันเองครับ
| String line = ""; while(client.available()){ line = client.readString(); } line[line.length() + 1] = '}'; Serial.print(line.lastIndexOf("{")); Serial.print(","); Serial.println(line.indexOf("}"));line = line.substring(line.lastIndexOf("{"),line.indexOf("}") + 1); Serial.println(line); |
ซึ่งต้องทำการปรับตัวแปร line เล็กน้อย ในที่นี้จะทำการเพิ่มตัวอักษร "{"
เพื่อให้ไลบรารี่ ArduinoJson ทำการแยกข้อมูลให้เรา
เนื่องจากเมื่อทดลองเอาข้อมูลทั้งหมดมาแยกจะไม่สำเร็จ เหมือนว่ารูปแบบของตัวแปร line ไม่ถูกต้อง
รูปแบบของ Json เป็นแบบ key:value ซึ่งจะถูกเรียกว่า JsonObject แต่จะมีรูปแบบ JsonArray
ที่ทำการเก็บ JsonObject หลายๆตัวรวมกัน สำหรับข้อมูลที่ส่งคืนมาจาก Dweet.io จะมีรูปแบบ JsonArray อยู่ด้วย
ซึ่งอาจจะทำให้เกิดข้อผิดพลาดขึ้น
ส่วนประกอบของข้อมูลที่ส่งคืนมา
{"this":"succeeded","by":"getting","the":"dweets",
"with":
[
{
"thing":"Node-RED-Supotsaeea",
"created":"2015-08-30T14:55:48.297Z",
"content":{"LED":1}
}
]
}
จะเห็นว่าส่วนของข้อมูลที่เราต้องการไปอยู่ในวงเล็บแบบ [ ] เป็นแบบอะเรย์
ยังไม่แน่ใจว่าเป็น bug ของไลบรารี่ ArduinoJon หรือไม่
แต่เพื่อแก้ไขปัญหาจึงดึงเอาข้อมูลเฉพาะ ส่วนของ content มา ซึ่งจริงแล้วตัวแปรที่เราต้องการ
ก็จะอยู่ในส่วนนี้เท่านั้น เอาว่าอันนี้เป็นรูปแบบเฉพาะของ Dweet.io ส่งมา ถ้าเป็น Service ของที่อื่น
อย่าง ThingSpeak อาจมีข้อแตกต่างกันไป
| StaticJsonBuffer<300> jsonBuffer; char json[300]; line.toCharArray(json, line.length()+1);JsonObject& root = jsonBuffer.parseObject(json); if(!root.success()){ Serial.println("parseObject() failed"); } else { const char* _LED = root["LED"]; Serial.print("LED:"); Serial.println(_LED); if(_LED) { if(_LED[0] == '1') digitalWrite(BUILTIN_LED - 2, HIGH); if(_LED[0] == '0') digitalWrite(BUILTIN_LED - 2, LOW); } } |
ส่วนนี้จะเป็นการแยกข้อมูลโดยใช้ ArduinoJson ผลของการแยกส่วนจะเก็บไว้ที่ตัวแปร root
ในลักษณะของอะเรย์ สำหรับของเรามีตัวแปร LED ตัวเดียว ก็ทำการเก็บค่าไว้ที่ตัวแปร _LED
const char* _LED = root[“LED”];
สมมุติว่ามีการฝากค่า RELAY ไว้ด้วย ก็ทำการดึงค่าเก็บใส่ตัวแปรไว้ได้
const char* _RELAY = root[“RELAY”];
การนำค่าไปใช้ต้องทำการตรวจสอบตัวแปรก่อนว่ามีอยู่หรือไม่
if(_LED)
{
if(_LED[0] == '1') digitalWrite(BUILTIN_LED - 2, HIGH);
if(_LED[0] == '0') digitalWrite(BUILTIN_LED - 2, LOW);
}
นำค่าที่ได้รับไปควบคุม LED ให้ติดหรือดับ
ทดลองปิดเปิด LED ด้วย browser หรือ Dashboard หรือ Flow ใน Node-RED editor ได้เลยครับ
บอร์ดอื่นไม่แน่ใจว่าจะต้องปรับอะไรหรือไม่ ตอนนี้มีบอร์ดนี้ให้ทดลองอยู่แบบเดียวครับ
ส่วนการปรับโปรแกรมด้วย editor ตัวอื่นๆ ก็คงต้องให้ผู้เชี่ยวชาญท่านอื่นช่วย
สำหรับผมคงใช้ Arduino IDE เป็นหลัก
โพสต์หน้าคงจะทดลองให้ส่งข้อความเตือนไปที่ tweeter ดูกันครับ
-------------------------------------------------------------------
Arduino Code (1.6.5)
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
const char* ssid = "ชื่อ WiFi router";
const char* password = "รหัสผ่าน";
const char* host = "dweet.io"; //ชื่อโฮสที่เก็บข้อมูล
void setup() {
Serial.begin(115200);
delay(10);
pinMode(BUILTIN_LED - 2, OUTPUT); // BUILTIN_LED ถูกกำหนดไว้ในไลบรารี่ ESP8266WiFi
Serial.println();
Serial.println();
Serial.print("Connection to ");
Serial.print(ssid);
WiFi.begin(ssid, password);
int count = 0;
while(WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
if(++count == 10){
Serial.println();
count = 0;
}
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
delay(500);
Serial.print("Connecting to ");
Serial.println(host);
WiFiClient client;
const int httpPort = 80;
if(!client.connect(host, httpPort)){
Serial.println("Connection failed");
return;
}
String url = "/get/latest/dweet/for/Node-RED-Supotsaeea";
Serial.print("Requesting URL: ");
Serial.println(url);
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Cache-Control: no-cache\r\n" +
"Connection: close\r\n\r\n");
delay(1000);
String line = "";
while(client.available()){
line = client.readString(); // .readStringUntil('\r');
}
line[line.length() + 1] = '}';
Serial.print(line.lastIndexOf("{")); Serial.print(","); Serial.println(line.indexOf("}"));
line = line.substring(line.lastIndexOf("{"),line.indexOf("}") + 1);
Serial.println(line);
StaticJsonBuffer<300> jsonBuffer;
char json[300];
line.toCharArray(json, line.length()+1);
JsonObject& root = jsonBuffer.parseObject(json);
if(!root.success()){
Serial.println("parseObject() failed");
} else {
const char* _LED = root["LED"];
Serial.print("LED:"); Serial.println(_LED);
if(_LED)
{
if(_LED[0] == '1') digitalWrite(BUILTIN_LED - 2, HIGH);
if(_LED[0] == '0') digitalWrite(BUILTIN_LED - 2, LOW);
}
}
Serial.println();
Serial.println("Close connection");
}
\r ใน Serial.print นี้คืออะไรหรอครับ
ตอบลบ