การใช้งาน UDP multicast สำหรับ ESP8266 ด้วย Arduino IDE

ก่อนอื่นต้องขออธิบายคำศัพท์ที่เกี่ยวข้องก่อนดังนี้ครับ UDP ย่อมาจาก User Datagram Protocol เป็นโปรโตคอลที่อยู่บน IP อีกทีหนึ่ง การรับส่งข้อมูลต่างๆจะขึ้นอยู่กับผู้ใช้งานว่าจะรับส่งอะไรบ้าง คล้ายๆกับการรับส่งข้อมูลผ่าน UART หรือ RS232 ไม่มีการตรวจสอบว่าข้อมูลที่ส่งไปนั้นถึงผู้รับหรือไม่ โดยผู้ใช้งานต้องเขียนโปรแกรมตรวจสอบความถูกต้องเอง ข้อดีของโปรโตคอล UDP คือใช้งานง่าย เขียนรับส่งข้อมูลโดยผู้ใช้เป็นคนกำหนดเอง
คำศัพท์ต่อไปก็คือ Unicast, Multicast, Broadcast Unicast คือการรับส่งข้อมูลระหว่าง IP ต่อ IP หรือเรียกว่าเครื่องต่อเครื่อง ส่วน Multicast เป็นการรับส่งข้อมูลเป็นกลุ่ม โดยจะกำหนดกลุ่มของ IP สำหรับ Multicast เอาไว้ ส่วน Broadcast เป็นการส่งข้อมูลไปยังทุกๆ IP ในเครือข่าย อุปกรณ์ที่เชื่อมต่อในเครือข่ายทั้งหมดจะได้รับข้อมูลที่ตัวส่ง ส่งออกมา

Jpeg

ESP8266 UDP Multicast

ในบทความนี้จะนำบอร์ด nodemcu 2 บอร์ด มาเขียนโปรแกรมเพื่อรอรับข้อมูลทาง UDP โดยจะรอรับข้อมูลบน IP address ที่เป็น IP สำหรับ Multicast คือ 239.0.0.57 แล้วส่ง IP address ของบอร์ดไปให้กับโปรแกรมบนคอมพิวเตอร์ โดยโปรแกรมบนคอมพิวเตอร์ที่ใช้สำหรับการรับส่งข้อมูลคือโปรแกรม Packet Sender มีทั้งแบบติดตั้งลงเครื่องและแบบ Portable ครับ

ด้านล่างเป็น Source code ที่ใช้เป็นตัวรับส่ง UDP Multicast เขียนบน Arduino IDE

// UDP multicast with ESP8266 by Jirawat Kongkaen
// www.micro.in.th
// 2015-09-22
// hardware use nodemcu v0.9

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

// เปลี่ยน SSID และ password ให้ตรงกับ Access point
char ssid[] = "**********";
char pass[] = "**********";

char packetBuffer[255];
char replyBuffer[255];

// พอร์ทและ IP address สำหรับ UDP multicast
unsigned int localPort = 5555;
byte ipMulti[] = { 239,0,0,57 };

WiFiUDP Udp;

void setup() {
  Serial.begin(115200);
  Serial.println();
  Serial.println();

  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, pass);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");

  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  Serial.println("Starting UDP");
  Udp.beginMulticast(WiFi.localIP(), ipMulti, localPort);
  Serial.print("Local port: ");
  Serial.println(Udp.localPort());

  pinMode(BUILTIN_LED, OUTPUT);
}

void loop() {
  // ตรวจสอบว่ามี packet UDP เข้ามาหรือยัง
  int packetSize = Udp.parsePacket();
  if (packetSize)
  {
    Serial.print("Received packet of size ");
    Serial.println(packetSize);
    Serial.print("From ");
    IPAddress remoteIp = Udp.remoteIP();
    Serial.print(remoteIp);
    Serial.print(", port ");
    Serial.println(Udp.remotePort());

    // อ่านข้อมูลจาก packet UDP แล้วเก็บไว้ที่ buffer
    int len = Udp.read(packetBuffer, 255);
    if (len > 0) packetBuffer[len] = 0;
    Serial.println("Contents:");
    Serial.println(packetBuffer);

    if(packetBuffer[0] == 'i' && packetBuffer[1] == 'p' && packetBuffer[2] == '?')
    {
      // ส่ง IP ของบอร์ด ESP8266 กลับไปยังคอมพิวเตอร์
      Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
      IPAddress ip = WiFi.localIP();
      sprintf(replyBuffer, "%d.%d.%d.%d\0", ip[0], ip[1], ip[2], ip[3]);
      Udp.write(replyBuffer);
      Udp.endPacket();
    }
  }
  
  blinkLed();
}

// LED กระพริบโดยไม่ใช้ delay
void blinkLed(void)
{
  static unsigned long previousMillis = 0;
  unsigned long currentMillis = millis();
  
  if(currentMillis - previousMillis >= 500)
  {
    previousMillis = currentMillis;
    if(digitalRead(BUILTIN_LED))
    {
      digitalWrite(BUILTIN_LED, LOW);
    }
    else
    {
      digitalWrite(BUILTIN_LED, HIGH);
    }
  }
}

รูปจาก Serial port monitor และโปรแกรม Packet Sender ที่ใช้สำหรับรับส่งข้อมูล UDP multicast
esp8266-udp-multicast-1
esp8266-udp-multicast-2 esp8266-udp-multicast-3