แสดงบทความที่มีป้ายกำกับ ESP32 แสดงบทความทั้งหมด
แสดงบทความที่มีป้ายกำกับ ESP32 แสดงบทความทั้งหมด

วันเสาร์ที่ 7 ธันวาคม พ.ศ. 2562

ESP32:Coding:Network:ThingSpeak

วิธีการเก็บค่า Sensor บน ThingSpeak

  ThingSpeak เป็นบริการเก็บข้อมูลโดยอิงกับเวลา เก็บไปเรื่อยๆเพื่อสร้างกราฟ สามารถนำไปวิเคราห์ด้วยโปรแกรม MathLAB ได้ ถ้าเก็บข้อมูลไม่มากนักใช้ได้ฟรี ก่อนใช้งานควรอ่านข้อจำกัดของบริการฟรีให้เรียบร้อย หลักๆคืออย่าส่งข้อมูลถี่จนเกินไป แนะนำให้ส่งทุกๆ 15นาทีหรือห่างกว่านั้น ในตัวอย่างจะส่งทุกๆหนึ่งนาที (6000 มิลลิวินาที)
    ไปที่ https://thingspeak.com/ ทำการ Sign Up ให้เรียบร้อยแล้ว สร้าง Channel แล้วเปิดใช้งาน field1 กับ field2 เพื่อเก็บค่า Hall และ Temperature นำค่า API Key มาใส่ในโค้ดด้านล่าง  ค่า "SSID" และ "password" ให้แก้เป็น Wifi ที่เราเชื่อมต่อ API ย่อมาจาก Application Programming Interface สำหรับคนไม่รู้จักดูความหมายได้ที่นี้
    ตัวอย่างนี้จะใช้เซนเซอร์ภายใน ESP32 อ่านค่าอุณหภูมิจากและสนามแม่เหล็ก(Hall) ค่าอุณหภูมิจะเป็นอุณหภูมิของ ESP32 ซึ่งจะสูงกว่าอุณหภูมิห้อง ตัวอย่างดัดแปลงมาจากเวปนี้ (แนะนำให้เข้าไปอ่านดู) สามารถเข้าไปดูวิธีการเซ็ตอัป ThingSpeak สำหรับตัวอย่างนี้ได้
การส่งข้อมูลด้านล่างจะเป็นแบบ Method GET คือส่งค่าผ่าน URL
สามารถทดสอบแบบง่ายๆโดยการใส่ลิงค์นี้ลงบนเว็บ เบราว์เซอร์
https://api.thingspeak.com/update.json?api_key=API_KEY&field1=1234&field2=35
แล้วไปดูกราฟ ใน Private View
ตรง #ifdef __cplusplus , extern "C" { , และ #endif สำหรับคนที่ไม่เชี่ยวชาญภาษา C++ อาจจะงงหน่อย นำไปใช้ก่อนแล้วกันมันจำเป็นสำหรับการเรียกใช้ฟังก์ชั่น temprature_sens_read() ซึ่งเป็นฟังก์ชั่นของระบบ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#ifdef __cplusplus
extern "C" {
#endif
uint8_t temprature_sens_read();
#ifdef __cplusplus
}
#endif
uint8_t temprature_sens_read();

#include <WiFi.h>
String apiKey = "API_KEY";  //ใส่ API Key ที่ได้รับจาก ThingSpeak
const char *ssid =  "SSID"; // Wifi ที่เชื่อมต่อ และรหัสผ่าน
const char *pass =  "password";
const char* server = "api.thingspeak.com";
WiFiClient client;
void setup() {
  Serial.begin(9600);
  delay(10);
  Serial.println("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) 
  {
      delay(500);
      Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
}

void loop() {
  //ใช้ GET method ฟอร์แม็ตเป็นดังข้างล่าง
  //https://api.thingspeak.com/update.json?api_key=API_KEY_HERE&field1=1234&field2=35
  int h = hallRead();
  float t = ((temprature_sens_read()-32)/1.8); //changing temperature parameter to celsius
  if (client.connect(server,80))
  {
    Serial.println("ThingSpeak  connected");      
    String url = "/update.json?api_key="+apiKey +"&field1=";
    url += String(h);
    url += "&field2=";
    url += String(t);

    Serial.print("Requesting URL: ");
    Serial.println(url);
    client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                 "Host: " + server + "\r\n" +
                 "Connection: close\r\n\r\n");
    unsigned long timeout = millis();
    while (client.available() == 0) {
      if (millis() - timeout > 20000) {
        Serial.println(">>> Client Timeout !");
        client.stop();
        return;
      }
    }
    while(client.available()) { //ข้อความที่ตอบกลับจาก server
      String line = client.readStringUntil('\r');
      Serial.print(line);
    }
  }else{
    Serial.println("Connection fail"); 
  }
  Serial.println("");
  client.stop();
  Serial.println("Waiting...");
  delay(60000); //รอหนึ่งนาที(60000 มิลลิวินาที)
}


ตัวอย่างด้านล่างนี้เป็นแบบ Method POST จะการส่งค่าเหมือนการส่งผ่านฟอร์มบนเวป


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#ifdef __cplusplus
extern "C" {
#endif
uint8_t temprature_sens_read();
#ifdef __cplusplus
}
#endif
uint8_t temprature_sens_read();

#include <WiFi.h>
String apiKey = "API_KEY"; //  ใส่ API Key ที่ได้รับจาก ThingSpeakconst char *ssid =  "ssid";          // ชื่อไวไฟที่ต่อ
const char *pass =  "password";   // รหัสผ่าน
const char* server = "api.thingspeak.com";
WiFiClient client;
void setup() 
{
  Serial.begin(9600);
  delay(30);
  Serial.println("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
}
void loop() 
{
  int h = hallRead();
  float t = ((temprature_sens_read()-32)/1.8); //ทำอุณหภูมิเป็นเซลเซียส

  if(client.connect(server,80))              //เชื่อมต่อไปยัง api.thingspeak.com
  {                          
    String postStr = apiKey;
    postStr +="&field1=";
    postStr += String(h);
    postStr += "&field2=";
    postStr += String(t);
    postStr += "\r\n\r\n";

    client.print("POST /update HTTP/1.1\n");
    client.print("Host: api.thingspeak.com\n");
    client.print("Connection: close\n");
    client.print("X-THINGSPEAKAPIKEY: "+apiKey+"\n");
    client.print("Content-Type: application/x-www-form-urlencoded\n");
    client.print("Content-Length: ");
    client.print(postStr.length());
    client.print("\n\n");
    client.print(postStr);
    
    unsigned long timeout = millis();
    while (client.available() == 0) {
      if (millis() - timeout > 20000) {
          Serial.println(">>> Client Timeout !");
          client.stop();
          return;
      }
    }
    while(client.available()) { //ข้อความที่ตอบกลับจาก server
      String line = client.readStringUntil('\r');
      Serial.print(line);
    } 
    Serial.print("");
    Serial.print("Hall: ");
    Serial.println(h);
    Serial.print("Temperature:");
    Serial.print(t);
    Serial.println(" C");                          
    Serial.println("%. Send to Thingspeak.");
  }else{
    Serial.println(h);
  }
  client.stop();
  Serial.println("Waiting...");
  delay(60000); //รอหนึ่งนาที(60000 มิลลิวินาที)
}

การใช้งานหน้าเวปจะมีลักษณะใช้งานRequest และ Respond
Request เพื่อขอหน้าเวป ด้วย Method GET หรือ POST จะมีการส่งข้อมูลพร้อมไปด้วย
Respond จะส่งหน้าเวปกลับมา หลังประมวลผลข้อมูลที่ส่งไป
ในภายหลังนิยมใช้เวปเซิร์ฟเวอร์เพื่อประมวลผลแทนการสร้างเซิร์ฟเวอร์เฉพาะทางแบบเดิมเลยมีคอนเซ็บของ Web API ขึ้นมา การติดต่อผ่านเวป(โปรโตคอล HTTP) จะต้องมีการส่งค่าบางอย่างไปด้วยจะทำให้ดูมีอะไรซับซ้อนหน่อย หลังจากทำการ Request ก็จะได้ค่าตอบกับมา เช่นสำเร็จ หาหน้าเวปไม่เจอ ฯลฯ ในตัวอย่างจะใช้ client.readStringUntil('\r'); เพื่ออ่านค่าที่ตอบกลับมาทีละบรรทัด ซึ่งจะพิมพ์ออก Serial Monitor ไม่ได้ใช้ทำอะไร เราควรรอให้เวปทำการ Respond เสียก่อนจะเลือกติดต่อเพราะไม่งั้นการ Request อาจจะล้มเหลวได้
    ถ้าใช้ Library Manager ติดตั้งไลบารีของ ThingSpeak  จะมีโค้ดตัวอย่างจะดูง่ายกว่าใช้ WiFiClient ดังที่ใช้ในตัวอย่างหน่อยหนึ่ง แต่เท่าที่ลองใช้มันมีปัญหากับไลบารี่บางตัว เลยแนะนำให้ใช้ดังตัวอย่างข้างต้น


เพิ่มเติม
NETPIE FEED vs ThingSpeak Channel




วันศุกร์ที่ 29 พฤศจิกายน พ.ศ. 2562

ESP32:Coding:Network:Time

Network Time from NTP Server

    อุปกรณ์ไฟฟ้าทั่วๆไป ถ้าขาดไฟฟ้า เช่นปิดอยู่จะไม่สามารถนับเวลาที่เดินไปเรื่อยๆได้ เปิดมาก็ต้องตั้งค่าเวลาใหม่ ถ้าต้องการค่าเวลาต้องต่อกับ Real Time Clock (RTC) ที่มีไฟเลี้ยง เพื่อให้นาฟิกาเดินไปเรื่อยๆ ซึ่งต้องมีค่าใช้จ่ายเพิ่ม และต้องตั้งเวลาใหม่เมื่อแบตเตอรี่หมด ถ้าอุปกรณ์สามารถต่อกับเน็ตเวิร์กได้  ก็จะดึงค่าเวลาจากเน็ตเวิร์กเพื่อตั้งเวลาและนับเวลาต่อไปเรื่อยๆได้ ในอินเตอร์เน็ตจะมีเซิร์ฟเวอร์ NTP ( Network Time Protocol) ใช้บอกเวลาให้เรา เป็นเวลามาตรฐาน Coordinated Universal Time (UTC) ซึ่งเป็นค่าเดียวกันทั่วโลก ในแต่ละท้องถิ่นจำเป็นต้องปรับจากค่านี้ให้ตรงกับเขตเวลาในแต่ละท้องถิ่น ประเทศไทยจะใช้ UTC+7 ก็คือเพิ่มจากเวลามาตรฐาน 7ช.ม. ค่าของโซนเวลาที่เราจะใช้ปรับกับเวลามาตรฐาน (Time Offset) ต้องเป็นหน่วยมิลลิวินาที โดยแปลงจากหน่วยชั่วโมง ยกตัวอย่าง
UTC -5 จะมีค่า -5 * 60 * 60 = -18000
UTC +7 จะมีค่า 7 * 60 * 60 = 25200
บางประเทศจะมีช่วงเวลากลางวันกลางคืนที่แตกต่างกันมากในแต่ละฤดูจำเป็นต้องปรับเวลาท้องถิ่นให้ตรงกับฤดูต่างๆ (Daylight saving time) แต่ประเทศไทยไม่จำเป็นต้องปรับ  เพราะกลางวันกลางคืนแตกต่างกันไม่มากจึงใช้ค่านี้เป็น Daylight Offset เป็น 0 การใช้ดูโค้ดตัวอย่าง
Examples/ESP32/Time/SimpleTime


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <WiFi.h>
#include "time.h"
const char* ssid       = "SSID";
const char* password   = "PASSWORD";
const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 25200; //UTC+7
const int   daylightOffset_sec = 0;//ไทยไม่ต้องปรับ
void setup()
{
  Serial.begin(9600); 
  //connect to WiFi
  Serial.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
  }
  Serial.println(" CONNECTED"); 
  //ดึงเวลาจากเซิร์ฟเวอร์ NTP แล้วเก็บในระบบ
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  printLocalTime(); //พิมออกมา
  //ไม่จำเป็นต้องใช้ Wifi อีกต่อไป
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
}
void loop()
{
  delay(1000);
  printLocalTime();
}
void printLocalTime()
{
  struct tm timeinfo; //ที่เก็บข้อมูลเวลา
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return;
  }//แสดงค่าด้วยวิธีต่างๆ
  Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
  Serial.print(asctime(&timeinfo));
  String date_time = String(timeinfo.tm_year+1900)+"/"+String(timeinfo.tm_mon+1)+"/"+String(timeinfo.tm_mday);
  date_time += " "+String(timeinfo.tm_hour)+":"+String(timeinfo.tm_min)+":"+String(timeinfo.tm_sec);
  Serial.println(date_time);
  Serial.println("");

}

ผลของโปรแกรมผ่าน Serial Monitor

Connecting to oom .... CONNECTED
Tuesday, December 03 2019 06:35:10
Tue Dec  3 06:35:10 2019
2019/12/3 6:35:10

Tuesday, December 03 2019 06:35:11
Tue Dec  3 06:35:11 2019
2019/12/3 6:35:11


หลังจากเรียกฟังก์ชั่น configTime() ค่าของเวลาจะเก็บไว้ในระบบเลย แล้วเราใช้ getLocalTime() เพื่อเรียกใช้


เพิ่มเติม
Getting Date & Time From NTP Server With ESP32
Time structure


วันอาทิตย์ที่ 17 พฤศจิกายน พ.ศ. 2562

Module:Environment:Dust

Dust Sensor Module

    โมดูลตรวจจับฝุ่น ทำการประมาณอนุภาคเล็กๆต่อปริมาตรอากาศ รุ่นที่ราคาถูกหน่อยใช้หลักการกระเจิงของแสง  อนุภาคขนาดต่างๆจะมีการกระเจิงแตกต่างกัน เซนเซอร์จะมีพัดลมดูดอากาศปริมาณน้อยเข้าไปผ่านตัววัด ดังนั้นค่าอาจจะไม่ได้สะท้อนความเป็นจริงของอากาศบริเวณนั้น นึกถึงน้ำขุ่นบริเวณต่างๆมันฟุ้งไม่เท่ากันอากาศก็เหมือนกัน จากประสบการณ์ค่าที่วัดได้จะแกว่งมาก เซนเซอร์สองตัววางติดกันค่าที่วัดได้อาจจะต่างกันถึง 10 หน่วยเลยทีเดียว แต่ค่าที่วัดโดยเฉลี่ยถ้าวัดถี่หน่อยทั้งวันก็จะใกล้เคียงกัน 

Plantower PMS x003

  รุ่น PMS1003, PMS3003, PMS5003, PMS6003, PMS7003 ใช้งานง่านผ่าน Serial Port ถือเป็นรุ่นยอดนิยมหาซื้อง่าย วิธีใช้งานเหมือนกัน ค่ามีการปรับเทียบจากโรงงานแล้ว(calibrate)  มีรุ่นที่ใช้เป็น I2C ด้วยแต่หาซื้อยากผมยังไม่เคยใช้ และมีรุ่นพิเศษที่เป็นรหัสลงท้าย ST จะอ่านอุณหภูมิ ความชื้น และ Formaldehyde ได้แต่หาซื้อยากราคาแพงรุ่นใหม่กว่าไม่ได้ต่างกันแต่มีขนาดเล็กลงมาก







  เซนเซอร์ต้องการไฟเลี้ยง 5V  แต่ขา RX TX ใช้ 3.3v ที่ผมเคยใช้คือ PMS7003 และ PMS5003 เป็นรุ่นยอดนิยมมี 6 สายที่ใช้งานได้
 ใช้ 4 เส้น(5v,GND,RX,TX) ก็ทำงานได้  
  • +5V - ไฟเลี้ยงเซนเซอร์
  •  0V  - Ground
  • TX  ส่งข้อมูลให้ไปต่อที่ RX ของไมโครคอนโทรลเลอร์
  • RX  รับข้อมูลให้ไปต่อที่ TX ของไมโครคอนโทรลเลอร์
  • Set ปกติปล่อยลอย(ไม่ต้องต่อ) หรือ ต่อวงจร Pullup 10K กับ GPIO ให้ High เพื่อ Wakeup หรือ Lowเพื่อ Sleep
  • Reset - ปกติปล่อยลอย(ไม่ต้องต่อ) หรือต่อ Pullup 10K กับ GPIO ถ้า ส่งลอจิก Low เพื่อ reset ตัวเซนเซอร์
ภาพล่างเป็นตัวอย่างขาของ PMS5003 จะมีสายที่มีหัวต่อสองด้านมา ผมตัดแล้วต่อวงจรหรือเข้าหัวเพื่อเชื่อมกับอุปกรณ์
 แนะนำให้ดูจาก DataSheet ของแต่ละรุ่นจะได้ต่อสายไม่พลาด
การใช้งานแบบทั่วอ่านค่าต่อแค่ 5V,Ground และ TX มันจะส่งค่า PM10 PM2.5 และ PM1 มาเรื่อยๆ
ถ้าจะรับคำสั่งเพื่อเซ็ตค่าก็ต้องต่อ RX กับ TX ของ MCU ทุกคำสั่งหรือข้อมูลจะขึ้นต้นด้วย 2 ไบต์แรก x42, x4D มีโหมดและคำสั่งดังนี้(ไปอ่าน Data Sheet จะมีอธิบาย)  ตอนส่งคำสั่งก็จะมีการตอบสนองกลับมา
Activate passive mode:
- request: 42 4D E1 00 00 01 70
- response: 42 4D 00 04 E1 00 01 74 

Activate active mode:
- request: 42 4D E1 00 01 01 71
- response: 42 4D 00 04 E1 01 01 75

Initiate measurement in passive mode:
- request: 42 4D E2 00 00 01 71
- response: one data telegram

Send to sleep:
- request: 42 4D E4 00 00 01 73
- response: 42 4D 00 04 E4 00 01 77 

Wake-up:
- request: 42 4D E4 00 01 01 74
- response: none


โดยสรุปจ่ายไฟจะเป็นโหมด Active จะมี respond เป็นค่าข้อมูลฝุ่นมาเรื่อยๆ ไม่หยุด ถ้าค่าฝุ่นมีการเปลี่ยนแปลงมากก็จะส่งถี่หน่อย ถ้าจะเปลี่ยนโหมดต้องส่งคำสั่ง เช่นส่งคำสั่งเพื่อเปลี่ยนเป็น Passive ต่างจาก Active ตรงที่ ถ้าต้องการอ่านค่าก็ต้อง ส่งคำสั่งเพื่อขอค่า  เซนเซอร์มีอายุการใช้งาน(ประมาณ 1-3 ปี) เราควรให้มัน Sleep เป็นระยะเพื่อยืดอายุการทำงานของเซนเซอร์ ถ้าจะอ่านค่าอีกทีต้อง Wakeup ล่วงหน้า 30 วินาทีแล้วค่อยเริ่มอ่านค่า จากประสบการณ์ที่เคยใช้จะมีโอกาสที่ส่งคำสั่ง sleep แล้วเซนเซอร์ไม่ยอม Sleep  แนะนำให้ใช้ขา set เพื่อควบคุมการ wakeup/sleep เนื่องจากเป็นเซนเซอร์ที่ใช้ภายในอาคาร ถ้าใช้ภายนอก ใช้ในครัว หรือในห้องน้ำ อาจจะต้องมีการออกแบบตัวป้องกันที่ดีพอเพราะฝุ่นหรือละอองน้ำอนุภาคใหญ่จะเข้าไปในตัวเซนเซอร์ได้ 
    สามารถใช้งานกับอุปกรณ์ทุกตัวที่รองรับการสื่อสารผ่านซีเรียลพอร์ต (ESP32,ESP8266,Raspberry PI,คอมพิวเตอร์ ฯลฯ) สามารถใช้ USB2Serial เพื่อใช้ต่อกับคอมพิวเตอร์ได้(PC/Mac ดูในภาพ) 

ESP32/ESP8266 ใช้ง่ายแค่ให้ติดตั้งไลบารี่ PMS เพิ่มจาก Library Manager แนะนำให้ดูตัวอย่างที่มากับ Library หรือจะอ่านค่าจาก Serial แล้วดึงออกมาเองก็ได้

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
1213
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//ESP32: อ่านค่าจากเซนเซอร์วัดฝุ่น PMS1003, PMS3003, PMS5003, PMS6003, PMS7003
//
#include "PMS.h"  // PMS Library by Mariusz Kachi Version 1.1.0
PMS pms(Serial2); // ต่อเซนเซอร์ที่ Serial2
PMS::DATA data;
#define RXD2 13 // ต่อ TX ของเซนเซอร์
#define TXD2 12 // ต่อ RX ของเซนเซอร์
void setup()
{
  Serial.begin(9600);
  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);   
  pms.passiveMode();    // ใช้โหมด passive mode ต้อง requestRead 
}
void loop()
{
  Serial.println("Waking up, wait 30 seconds for stable readings...");
  pms.wakeUp(); //ปลุกเซนเซอร์ขึ้นมาทำงาน
  delay(30000);
  Serial.println("Send read request...");
  pms.requestRead(); //ขอข้อมูล จากเซนเซอร์ ของโหมด passive
  Serial.println("Reading data...");
  if (pms.readUntil(data))
  {
    Serial.print("PM 1.0 (ug/m3): ");
    Serial.println(data.PM_AE_UG_1_0);

    Serial.print("PM 2.5 (ug/m3): ");
    Serial.println(data.PM_AE_UG_2_5);

    Serial.print("PM 10.0 (ug/m3): ");
    Serial.println(data.PM_AE_UG_10_0);
  }
  else
  {
    Serial.println("No data.");
  }
  Serial.println("Going to sleep for 60 seconds.");
  pms.sleep(); //พักการทำงานของเซนเซอร์
  delay(60000);
}

สำหรับ Raspberry PI  ต้องเปิดใช้งาน Serial Port ก่อน สำหรับคอมพิวเตอร์(PC/Mac) ให้ต่อผ่าน USB to Serial Adapter มีโค้ดตัวอย่างหาได้ง่ายส่วนใหญ่เป็น Python ผมเขียนไม่เป็นเลยหาที่เป็น JavaScript(Node.js) มี Library ให้ใช้งานแต่ปัญหาเยอะเหมือนกัน ยังมีไลบารีพื้นฐาน  Node SerialPort ซึ่งจำเป็นต้องคอมไฟล์โค้ดด้วย สำหรับ Windows ต้องติดตั้ง C++ build tools ก่อน เนื่องจาก Library สำหรับอ่านค่าฝุ่นมีปัญหาและไม่ได้อัปเดต ผมเลยเขียนแบบง่ายๆขึ้นมาเองใช้แค่ Node SerialPort แก้ค่า COM3 เป็นค่าของเครื่องที่ใช้คร้บ สำหรับ Linux จะเป็นหน้าตาประมาณนี้ /dev/ttyAMA0


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
var SerialPort = require("serialport")
var serialPort = new SerialPort("COM3", {
	baudRate: 9600,
})
function processData(info) {
	var s = ""
	for (var j = 0; j < info.length; j++) {
		s = s + ":" + info[j].toString(16)
	}
	console.log("Data", info)
	var temp2, tem1, pm1, pm2_5, pm10, n03, n05, n1, n25, n5, n10
	pm1 = (info[4] << 8) | info[5]
	pm2_5 = (info[6] << 8) | info[7]
	pm10 = (info[8] << 8) | info[9]
	console.log("pm1 :" + pm1 + ", pm2.5 :" + pm2_5 + ", pm10 :" + pm10)

	pm1 = (info[10] << 8) | info[11]
	pm2_5 = (info[12] << 8) | info[13]
	pm10 = (info[14] << 8) | info[15]
	console.log("pm1a:" + pm1 + ", pm2.5a:" + pm2_5 + ", pm10a:" + pm10)

	n03 = (info[16] << 8) | info[17]
	n05 = (info[18] << 8) | info[19]
	n1 = (info[20] << 8) | info[21]
	n25 = (info[22] << 8) | info[23]
	n5 = (info[24] << 8) | info[25]
	n10 = (info[26] << 8) | info[27]

	console.log("n03:" + n03 + ",n05:" + n05 + ",n1:" + n1 + 
                ",n25:" + n25 + ",n5:" + n5 + ",n10:" + n10)
}

function init() {
	serialPort.on("open", function () {
		// sleep  0x42, 0x4D, 0xE4, 0x00, 0x00, 0x01, 0x73
		// wakeup 0x42, 0x4D, 0xE4, 0x00, 0x01, 0x01, 0x74
		// active 0x42, 0x4D, 0xE1, 0x00, 0x01, 0x01, 0x71
		// passive 0x42, 0x4D, 0xE1, 0x00, 0x00, 0x01, 0x70
		// request read 0x42, 0x4D, 0xE2, 0x00, 0x00, 0x01, 0x71
		serialPort.write(Buffer.from([0x42, 0x4d, 0xe4, 0x00, 0x01, 0x01
                    , 0x74, 0x42, 0x4d, 0xe1, 0x00, 0x01, 0x01, 0x71]), 
                function (err) {
			if (err) {
				return console.log("Error on write : ", err.message)
			}
			console.log("message written")
		})
		var sign = 0
		counter = 0
		a = new Array(32).fill(0)

		serialPort.on("data", function (data) {
			//console.log('data received: ' + data);
			//console.log( data[0].toString() + ":"+ data.byteLength );
			for (var i = 0; i < data.byteLength; i++) {
				if (counter == 0 && data[0] != 0x42) return
				if (counter == 1 && data[i] != 0x4d) {
					counter = 0
					return
				}
				a[counter] = data[i]
				counter++
				if (counter == a.length) {
					counter = 0
					sign = 1
				}
				//process array
				if (sign) {
					sign = 0
					processData(a)
				}
			}
		})
	})
}
init()

ผมแก้ไข Library จากของเดิมใหม่แต่มีหลายไฟล์ ไว้ขึ้น Git แล้วจะมาอัปเดตที่นี้ครับ

เพิ่มเติม


Shinyei Model PPD42NS Dust Sensor

เป็นเซนเซอร์แบบอนาล็อก คิดว่าน่าจะต้องมีเครื่องวัดที่เที่ยงตรงอีกตัวแล้วทำการ calibrate  ผมมีอยู่ตัวหนึ่งถ้ามีเวลาจะเอามาลองใช้ ตอนนี้ให้ดูตัวอย่างในลิงค์นี้ จะต้องต่อ Voltage Devider เพื่อให้ใช้กับ 3.3โวลต์ได้



ข้อมูลทั่วไป



วันเสาร์ที่ 9 พฤศจิกายน พ.ศ. 2562

ESP32:Coding:Basic

โค้ดสำหรับผู้เริ่มหัดใช้งาน

  สำหรับผู้เริ่มต้นใช้ ESP32 ต้องสามารถอัปโหลดโปรแกรมขึ้นบอร์ดให้ได้ก่อน แล้วลองใช้โค้ดตัวอย่างที่มีใน Arduino IDE สำรวจ บอร์ดของเราก่อนว่ามี ปุ่มหรือไฟ LED ให้ใช้งานหรือไม่  ดูจากคู่มือบอร์ดที่เราใช้ ตัวอย่างในหน้านี้อาจจะมีการดัดแปลงเล็กน้อยเพื่อให้สะดวกต่อการใช้งาน  แนะนำให้เลือกโค้ดที่ ใช้ ปุ่มBOOT, LED ,Wifi ,Blue, tooth , sensor ที่มากับบอร์ด จะได้ไม่ต้องต่ออุปกรณ์เพิ่ม พอคุ้นเคยแล้วถึงเริ่มต่ออุปกรณ์แล้วเขียนโค้ดเพื่อใช้งาน
ตัวอย่างที่อยู่ใน Arduino IDE


จากภาพ Build in Example จะเป็นตัวอย่างที่ใช้กับ Arduino  บางตัวอย่างใช้กับ ESP32 ได้ บางตัวอย่างก็ใช้ไม่ได้ เช่นที่ใช้ฟังก์ชั่น analogWrite() ซึ่ง ESP32 ไม่รองรรับ ส่วนตัวอย่างที่ใช้ได้กับ ESP32 จะอยู่จะอยู่ด้านล่างๆ ที่เขียนว่า Example for [ชื่อบอร์ด ESP32]
สำหรับวิธีการใช้ฟังชั่นต่างๆและไวยากรภาษา C สามารถดูได้จากเมนู Help/Reference ใน Arduino IDE ได้เลย

Examples/01.Basics/Blink

ตัวอย่างไฟกระพริบทุกๆหนึ่งวินาที ถ้าบอร์ดมี LED ในตัวหรือ แล้วเลือกบอร์ดบน Arduino IDE ได้ถูกรุ่น จะมีการประกาศค่า LED_BUILTIN ไว้เรียบร้อยแล้ว ว่าเป็นขาไหน (บางรุ่นก็ไม่ประกาศก็จะคอมไฟล์ไม่ผ่าน) ผมขอแก้นิดหน่อยเพื่อให้คอมไฟล์กับบอร์ดไหนก็ได้ แต่ต้องแก้ค่า led_pin ให้ตรงกับขาที่เป็น LED

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
int led_pin = 13; //ใส่เลขขา LED หรือใช้ LED_BUILTIN ก็ได้
void setup() {
  pinMode(led_pin, OUTPUT); //กำหนดให้ led_pin เป็น OUTPUT(ส่งค่าออก)
}
void loop() {
  digitalWrite(led_pin, HIGH);   // เปิดไฟ (HIGH มีค่าเป็น 1)
  delay(1000);                   // รอ 1000 มิลลิวินาที(1วินาที)
  digitalWrite(led_pin, LOW);    // ปิดไฟ (LOW มีค่าเป็น 0)
  delay(1000);                   // รอ 1000 มิลลิวินาที(1วินาที)
}

pinMode(pin_number, INPUT);  กำหนด ขา(pin_number)ให้เป็นขาสำหรับรับค่า INPUT (กำหนดได้ 3 ค่า INPUT, OUTPUT, INPUT_PULLUP)
digitalWrite(pin_number, 0_or_1);  คำสั่งนี้จะเขียน 0(LOW) หรือ 1(HIGH) ไปที่ขาที่กำหนดใน pin_number
delay(1000) จะเป็นการหยุดรอ เป็นจำนวนมิลลิวินาที ดังนั้น 1000มิลลิวินาทีก็คือหนึ่งวินาที
ลองเปลี่ยนค่า delay แล้วดูการเปลี่ยนแปลงของการกระพริบ สำหรับผู้ที่ต่อไฟ LED เพิ่มเอง ควรใช้ตัวต้านทานซัก 330 - 1K โอมห์ ร่วมด้วย ระวัง LED ต่อกลับข้างไฟจะไม่ติด
 ต่อหลอด LED กับ ESP32

Examples/02.Digital/Button

กดปุ่มเพื่อปิดหรือเปิดไฟ บอร์ดหลายรุ่นมีปุ่ม Boot ซึ่งต่อกับขา 0 เรานำมาใช้ได้ (ปุ่ม EN หรือ Reset ไม่สามารถอ่านค่าด้วยโค้ดได้)คล้ายตัวอย่างที่แล้วเพิ่มการอ่านปุ่มเข้ามา ใช้ปุ่มเพื่อปิดเปิด LED มีการแก้โค้ดเดิมนิดหน่อยให้กระชับขึ้น


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const int buttonPin = 0;// เลขขาที่ต่อปุ่ม ปุ่ม BOOT อยู่ที่ขา 0
const int ledPin =  4;  // ใส่เลขขา LED หรือใช้ LED_BUILTIN ก็ได้
int buttonState = 0;    // ตัวแปรเก็บสถานะ LOW/HIGH ของปุ่ม
void setup() {
  pinMode(ledPin, OUTPUT);   //กำหนดให้ ledPin เป็น OUTPUT(ส่งค่าออก)
  pinMode(buttonPin, INPUT); //กำหนดให้ buttonPin เป็น INPUT(รับค่าเข้า)
}
void loop() {
  buttonState = digitalRead(buttonPin);
  digitalWrite(ledPin, buttonState);
}

digitalRead(pin_number); ฟังก์ชั่นนี้จะอ่านค่าสถานะ(0 หรือ 1 )จากขา
โปรแกรมอ่านสถานะของปุ่มด้วย digitalRead ไปเก็บในตัวแปร buttonState แล้วนำค่าใน buttonState ส่งออกไปด้วย digitalWrite สู่หลอด LED
ปุ่ม BOOT จะให้ค่าเป็น LOW ก่อนกดปุ่มแล้วจะให้ HIGH เมื่อกดปุ่ม


คำถาม : ถ้าจะให้ปุ่มทำงานตรงกันข้ามกับที่เป็นอยู่ตอนนี้จะต้องแก้โค้ดอย่างไร

ถ้าบอร์ดไม่มีปุ่ม BOOT หรืออยากต่อปุ่มเอง จำเป็นต้องใช้วงจร Pull Up เพื่อให้ขาอยู่สถานะที่ถูกต้อง ใน ESP32 มีวงจร Pull up อยู่ในตัวสามารถเรียกใช้ได้เลย ให้ต่อสวิตซ์ด้านหนึ่งกับ GND อีกด้านต่อกับขาใดขาหนึ่งที่อ่านค่าดิจิตอลได้ นำโค้ด ก่อนหน้ามาแก้ตรง
pinMode(buttonPin, INPUT); 
ให้เป็น
pinMode(buttonPin, INPUT_PULLUP); 



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const int buttonPin = 6;// เลขขาที่ต่อปุ่มที่ขา 6
const int ledPin =  22;  // ใส่เลขขา LED ที่ขา 22
int buttonState = 0;    // ตัวแปรเก็บสถานะ LOW/HIGH ของปุ่ม
void setup() {
  pinMode(ledPin, OUTPUT);   //กำหนดให้ ledPin เป็น OUTPUT(ส่งค่าออก)
  pinMode(buttonPin, INPUT_PULLUP); //กำหนดให้ buttonPin เป็น INPUT(รับค่าเข้า)
}
void loop() {
  buttonState = digitalRead(buttonPin);
  digitalWrite(ledPin, buttonState);
}

ปุ่มต่อขา16 หลอด LED ต่อขา 22 ใช้ตัวต้านทาน 1Kโอมห์

Examples/01.Basics/DigitalReadSerial

   เวลาบอร์ดต่อก้บคอมพิวเตอร์จะติดต่อสื่อสารกันผ่านพอร์ตซีเรียล เป็นการสื่อสารแบบอนุกรม ส่งข้อมูลเรียงๆกันไปเป็นจังหวะ(baud rate)ที่รู้กันระหว่างสองฝั่ง จะไม่อธิบายรายละเอียดในที่นี้  ขอให้รู้เพียงว่าเป็นการสื่อสารประเภทหนึ่งก็พอ  ขณะอัปโหลดโปรแกรมจะใช้เพื่อส่งโปรแกรมที่คอมไพล์เสร็จแล้วไปใส่ไว้ในบอร์ด หลังจากนั้นพอร์ตซีเรียลก็จะนำไปใช้งานอื่นได้ ตัวอย่างนี้จะใช้เพื่อส่งข้อความจากบอร์ดไปคอมพิวเตอร์ มีประโยชน์มากคือใช้ดีบักโปรแกรม เพราะบอร์ดส่วนใหญ่จะไม่มีจอแสดงผล ส่งข้อมูลกลับมาที่จอคอมพิวเตอร์จะได้รู้ว่าโปรแกรมทำงานไปถึงไหนแล้ว ตัวแปรมีค่าอะไร ในเมนู Tools/Serial Monitor จะมีโปรแกรมสำหรับรับและส่งค่าไปที่พอร์ตซีเรียล ถ้าข้อมูลที่ส่งมาเป็นตัวเลขเรานำมาแสดงเป็นกราฟได้ด้วย  Tools/Serial Plotter 


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
int pushButton = 0; 
void setup() {
  Serial.begin(9600); //ความเร็วหรือจังหวะการรับส่งข้อมูล
  pinMode(pushButton, INPUT);
}
void loop() {
  int buttonState = digitalRead(pushButton);
  Serial.println(buttonState);//ส่งค่า 0 หรือ 1 ไปที่พอร์ตซีเรียล
  delay(10); 
}
ตัวอย่างโค้ดจะอ่านค่าจากปุ่ม BOOT แล้วส่งค่าไปที่พอร์ตซีเรียล ถ้าเปิด Serial Monitor จะเห็นค่า 0 กับ 1 ทีละบรรทัด
Serial.begin(9600); ฟังก์ชั่นนี้จะกำหนดจังหวะการรับส่ง่ข้อมูล ใน Serial Monitor ก็ต้องเซ็ตเป็นค่าเดียวกันถึงจะรับส่งข้อมูลได้
Serial.println(buttonState); ส่งค่า buttonState ไปออกพอร์ตซีเรียล และปิดท้ายด้วยขึ้นบรรทัดใหม่(ส่งอักขระ Enter) ถ้าใช้ Serial.print() จะไม่มีเครื่องหมายขึ้นบรรทัดใหม่ปิดท้าย

DigitalReadSerial แสดงใน Serial Plotter

Examples/ESP32/Touch/TouchRead

ESP32 มีปุ่มสัมผัส ไม่ต้องต่ออะไรเพิ่มแค่ใช้นิ้วมือแตะก็พอ ใช้การตรวจสอบประจุไฟฟ้าที่ขา จะมีบางขาที่ทำปุ่มสัมผัสได้  ยกตัวอย่าง(ภาพล่าง)ผังการวางขาของบอร์ดรุ่นหนึ่ง เราจะเห็น Touch5 อยู่ขา 12 จะสำหรับบอร์ดนี้ T5 จะแทนค่า 12 (มี T0-T9)




โค้ดของโปรแกรมตัวอย่างจะคล้ายกับ DigitalReadSerial ที่ผ่านมาแต่ค่าที่อ่านได้จะไม่ใช่ 0/1 จะเป็นค่าที่ไม่ค่อยนิ่งเท่าไหร่ขึ้นกับความชื้นและวิธีการสัมผัส ทดสอบโดยใช้นิ้วแตะที่ขา T5 เราสามารถใช้เลข 12 แทนก็ได้


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
void setup()
{
  Serial.begin(115200); //จังหวะการส่งข้อมูล
  delay(1000); // give me time to bring up serial monitor
  Serial.println("ESP32 Touch Test");
}
void loop()
{
  Serial.println(touchRead(T5));// อ่านค่าจากขา T5 แล้วส่งออกพอร์ตซีเรียล
  delay(1000);
}
ในกราฟด้านล่างเมื่อแตะขา 12 ค่าจะตกลงมา
TouchRead แสดงค่าใน Serial Plotter


เพิ่มเติม

Examples/ESP32/Fading/LEDSoftwareFade

การปรับความสว่างของหลอด LED สามารถใช้การต่อตัวต้านทานแบบปรับค่าได้อนุกรมกัน โวลต์ตกคร่อมหลอดไฟก็จะอยู่ระหว่าง 0-3.3โวลต์(อนาล็อก)  แต่ ESP32 ไม่สามารถส่งค่าออกเป็นอนาล็อกได้  เลยส่งเป็นสัญญาณ เปิดปิดถี่ๆสลับกัน ถ้าไฟสว่างก็ให้ช่วงการเปิดนานกว่าปิด ถ้าหรี่ไฟก็ให้มีช่วงที่ปิดนานขึ้น การทำแบบนี้เรียก PWM  ขา GPIOs 34 ถึง 39 ใช้ PWM ไม่ได้ อ่านเพิ่มเติมได้จากลิงค์ด้านล่าง
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
const int ledPin=2; // ใส่เลขขา LED หรือใช้ LED_BUILTIN ก็ได้
const int freq = 5000;     // ความถี่
const int ledChannel = 0;  // ช่องของ PWM ,มี 16 channel
const int resolution = 8; // ความละเอียด 8บิต
void setup(){
  ledcSetup(ledChannel, freq, resolution); //ช่อง,ความถี่,ความละเอียด
  ledcAttachPin(ledPin, ledChannel);// เชื่อม channel เข้ากับขา GPIO
}
void loop(){
  // increase the LED brightness
  for(int dutyCycle = 0; dutyCycle <= 255; dutyCycle++){   
    ledcWrite(ledChannel, dutyCycle);// ส่งเออกป็น PWM ที่ channel ที่กำหนด
    delay(15);
  }
}

เพิ่มเติม

Examples/ESP32/HallSensor

ในตัวชิป ESP32 จะมีเซนเซอร์วัดสนามแม่เหล็ก เราสามารถเรียกดูค่าได้จากฟังก์ชั่น hallRead()  ให้นำแม่เล็กแรงสูงมาจ่อที่ชิป แล้วดูค่าผ่าน Serial Plotter

1
2
3
4
5
6
7
8
//อ่านค่าจาก Hall Sensor ไปแสดงที่ Serial
//ใช้แม่เหล็กแรงสูงเพื่อทดสอบ
void setup() {
  Serial.begin(9600);
}
void loop() { 
  Serial.println(hallRead());
}

Examples/Wifi/WifiScan

   ค้นหา Wifi Access Point ที่อยู่ใกล้เคียงแล้วแสดงชื่อพร้อมความแรงสัญญาณ ตัวอย่างนี้จะใช้ Library เพิ่มเติมโดยตรงบรรทัดแรกจะเห็น
#include "ไฟล์ header ของ Library"
สามารถศึกษาการใช้ไลบารี่เพิ่มเติมได้ที่นี้


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include "WiFi.h" //ใช้ Library เกี่ยวกับ Wifi
void setup()
{
    Serial.begin(115200);
    WiFi.mode(WIFI_STA); //ใช้โหมด Station
    WiFi.disconnect(); //ตัดการเชื่อมต่อกัย Access point (ถ้าต่ออยู่)
    delay(100);
    Serial.println("Setup done");
}
void loop()
{
    Serial.println("scan start");
    int n = WiFi.scanNetworks(); //ค้นหา Access Point ที่อยู่รอบๆ,n จำนวนที่พบ
    Serial.println("scan done");
    if (n == 0) {
        Serial.println("no networks found");
    } else {
        Serial.print(n);
        Serial.println(" networks found");
        for (int i = 0; i < n; ++i) {
            // Print SSID and RSSI for each network found
            Serial.print(i + 1);
            Serial.print(": ");
            Serial.print(WiFi.SSID(i)); //Service Set Identifier(ชื่อ Access Point)
            Serial.print(" (");
            Serial.print(WiFi.RSSI(i)); //Received signal strength(ความแรงสัญญาณ)
            Serial.print(")");
            Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN)?" ":"*");
            delay(10);
        }
    }
    Serial.println("");
    delay(5000); //รอซักครู่ก่อนค้นหารอบต่อไป
}

WifiScan: ชื่อ Accesspoint แสดงใน Serial Monitor

Examples/Wifi/WifiAccessPoint

    ตัวอย่างนี้ยาวหน่อย เป็นการสั่งปิดเปิดไฟผ่านเวป ESP32 จะกระจายสัญญาณ Wifi (Access Point) สามารถใช้มือถือหรือคอมพิวเตอร์เชื่อมต่อได้แต่ออกอินเตอร์เน็ตไม่ได้ เปิดเวปบราวเซอร์แล้วไปที่ IP Address ของ ESP32 ก็จะเห็นหน้าเวป มีลิงค์ให้เลือกปิดเปิดหลอด LED ที่อยู่บนบอร์ด
การสื่อสารด้วยเวป(โปรโตคอล HTTP) จะประกอบไปด้วย request กับ response
Request: คอมพิวเตอร์ร้องขอไปที่เซิร์ฟเวอร์
Response: เวปเซิร์ฟเวอร์ตอบกลับมา
เช่นมือถือ(client)ร้องขอหน้าเวป https://www.google.com
เวปเซิร์ฟเวอร์ของ google ตอบกลับโดยส่งหน้าเวปกลับมาแสดงที่มือถือ ลองดูวีดีโอของโค้ดที่เราจะลองอัปโหลด


โค้ดก็อปไปใช้ได้เลย

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <WiFi.h>
#include <WiFiClient.h>
#include <WiFiAP.h>
//#define LED_BUILTIN 2   //ถ้าบอร์ดมีการกำหนดค่านี้แล้วให้คอมเมนต์บรรทัดนี้ออกหรือกำหนดเลขขาให้ถูกถ้าไม่มี
const char *ssid = "yourAP"; //ชื่อ Access point ที่เราสร้างขึ้น
const char *password = "yourPassword"; //รหัสผ่านของ Access point
WiFiServer server(80);
void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(115200);
  Serial.println();
  Serial.println("Configuring access point...");
  WiFi.softAP(ssid, password); // ถ้าไม่ต้องการให้มีการใส่รหัสผ่านให้เอา password ออก
  IPAddress myIP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(myIP);
  server.begin();
  Serial.println("Server started");
}

void loop() {
  WiFiClient client = server.available();   // รอ client ติดต่อมา
  if (client) {                             // มีอุปกรณ์(client)ต่อเชื่อมเข้ามา
    Serial.println("New Client.");          
    String currentLine = "";                // สร้าง String เพื่อเก็บข้อมูลจาก client
    while (client.connected()) {            // ลูปวนรอขณะที่มีการเชื่อมต่อจาก client
      if (client.available()) {             // ถ้ามีข้อมูลที่ยังสามารถอ่านได้จาก client
        char c = client.read();             // อ่านมาหนึ่งไบต์เก้บไว้ในตัวแปร c (อ่านทีละตัวอักษร)
        Serial.write(c);                    
        if (c == '\n') {                    // ถ้าขึ้นบรรทัดใหม่(อักขระ new line)
          // ถ้าพบการขึ้นบรรรทัดใหม่ ที่ต้นบรรทัด(currentLine เป็น 0 )
          // อีกความหมายหนึ่งก็คือเจอขึ้นบรรทัดใหม่สองรอบ จะเป็นการจบ  HTTP request ดังนั้นส่ง response ได้
          if (currentLine.length() == 0) {
            // ต้องส่งสามบรรทัดก่อนส่งข้อมูล 1.ส่วนหัว, 2.ชนิดข้อมูล, 3.ตบท้ายด้วยบรรทัดว่างๆ
            client.println("HTTP/1.1 200 OK"); // ส่วนหัวของ HTTP จะต้องส่งโค้ดบอกสถานะ
            client.println("Content-type:text/html"); //เพื่อให้ client รู้ว่าข้อมูลที่ส่งกลับเป็น HTML
            client.println();//บรรทัดว่าง
            // ส่งข้อมูลเป็นหน้าเวปกลับไป
            client.print("Click <a href=\"/H\">here</a> to turn ON the LED.<br>");
            client.print("Click <a href=\"/L\">here</a> to turn OFF the LED.<br>");
            client.println();// ปิดจบด้วยบรรทัดว่าง
            break; //ออกจากลูป while
          } else {    
            currentLine = ""; //จบหนึ่งบรรทัดทำให้ว่างเตรียมบรรทัดใหม่
          }
        } else if (c != '\r') { // ถ้าคุณได้อักขระใดๆที่ไม่ใช่ carriage return
          currentLine += c;     // เอาตัวอักษรนั้นไปต่อในบรรทัด( carriage return จะทิ้งไป)
        }

        // ถ้าได้ "GET /H" หรือ "GET /L" ในท้ายบรรทัด// ถ้าได้ "GET /H" หรือ "GET /L" ในท้ายบรรทัด
        if (currentLine.endsWith("GET /H")) {
          digitalWrite(LED_BUILTIN, HIGH);   // เปิดไฟ
        }
        if (currentLine.endsWith("GET /L")) {
          digitalWrite(LED_BUILTIN, LOW);    // ปิดไฟ
        }
      }
    }//จบ while
    client.stop(); //จบการเชื่อมต่อกับ client
    Serial.println("Client Disconnected.");
  }
}

โค้ดนี้จำเป็นต้องมีความรู้เรื่องเวปและ HTML มาบ้าง ส่วนโค้ดที่เป็นแสดงหน้าเวปจะเป็นสองบรรทัดล่างนี้
Click here to turn ON the LED
Click here to turn OFF the LED

แต่เวลาเขียนเป็นโค้ดภาษา C ถ้าตัวหนังสือจะแสดงเครื่องหมายคำพูดต้องใช้เครื่องหมาย \ ไว้หน้าเสมอเพื่อจะได้ไม่กลายเป็นหมายคำพูดของต้นและท้ายประโยค
เวลาเปิดไฟคลิ้กที่ลิงค์ก็จะไปที่ http://192.168.4.1/H ถ้าปิดไฟจะเป็นลิงค์ http://192.168.4.1/L




Module:Control:IFR 520

MOSFET Module  สวิตซ์ปิดเปิดไฟเหมือน Relay แต่เป็น Solid state (ไม่มีส่วนที่เคลื่อนไหว) มันทำงานที่ความถี่สูงได้เหมาะกับเอาไปใช้งาน PWM ...