วันพฤหัสบดีที่ 10 กันยายน พ.ศ. 2558

NodeRED : ESP8266 กับ Webconfig

 

ผมเคยพูดถึงความไม่สะดวกในการนำ ESP8266 ไปใช้งานจริง เนื่องจากการนำไปใช้ในต่างสถานที่ ทั้ง SSID และ Password ที่เปลี่ยนไป จะทำให้ ESP8266 กลายเป็นที่ทับกระดาษ (แต่ขนาดเล็กอาจจะปลิวไปกับกระดาษ) แม้ว่าจะอยู่ที่เดิม แต่บางครั้ง DHCP server แจกจ่าย IP address ให้ต่างจากเดิม ก็จะไม่สามารถทำงานได้

 

ในส่วนที่ไม่ทราบหมายเลข IP ก็มีการนำ OLED ขนาดเล็กๆมาแสดงหมายเลข IP ก็สามารถแก้ไขได้ แต่ถ้าเราต้องการนำอุปกรณ์ไปใช้ในต่างสถานที่ มี SSID และ Password ต่างออกไป ก็ไม่สามารถนำวิธีการนี้ไปใช้ได้

 

หลายท่านคงเคยตั้งค่า router ที่สามารถเปลี่ยนค่าต่างๆได้ ด้วยการต่อสายแลน แล้วเปิด Browser ที่ 192.168.1.1 จะแสดงช่องต่างๆ ให้เราป้อนค่า และบันทึก

 

วิธีการข้างต้นเป็นการเขียนเวบ เหมือนที่เราเคยเขียนกัน และนำค่าที่เราป้อนไปบันทึกไว้ในหน่วยความจำ หน่วยความจำเป็นแบบบันทึกและล้างข้อมูลด้วยไฟฟ้า ชื่อย่อคือ EEPROM (Electrically Erasable Programmable Read Only Memory) จากการที่บันทึกและล้างข้อมูลด้วยไฟฟ้า ทำให้ข้อมูลยังคงอยู่แม้ไม่มีไฟเลี้ยง

 

ESP8266 มีหน่วยความจำรูปแบบนี้ขนาด 4K-bytes เพียงพอที่จะเก็บข้อมูล

 

ช่วงที่ผมเขียนบล็อก และได้ติดตามโพสต์ของ ESP8266 Thailand ก็ได้รับทราบจากเพื่อนสมาชิกท่านหนึ่งส่งลิ้งค์ไปที่ไซท์ของคุณ John Lassen ผมได้อ่านทำความเข้าใจแล้วเห็นว่ามีประโยชน์และสามารถต่อเนื่องบทความที่กำลังเขียนได้

 

ผมได้ส่งอีเมล์ไปพูดคุยกับคุณ John เพื่อขออนุญาตในการนำทั้งหมดหรือบางส่วนของบทความที่เค้าเขียนมาใช้ในบล็อกของผม  คุณ John ตอบมาว่ายินดีและยังเพิ่มเติมว่าจะทำการอัพเดพเนื้อหาในบทความของเค้าให้ดียิ่งขึ้น

image        image

http://www.john-lassen.de/index.php/projects/esp-8266-arduino-ide-webconfig

ผู้อ่านที่ต้องการศึกษาโดยละเอียด สามารถเข้าอ่านบทความเต็มได้จากลิ้งค์ด้านบน

 

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

Download

หรือ

https://www.dropbox.com/s/ldszaffy6c1omwe/ESP_WiFi_AccessPoint.zip?dl=0

เปิดโค๊ดด้วย Arduino 1.6.2 และอัพโหลด ถ้าการทำงานเป็นปกติ ให้ทดลองเปิดดูรายชื่อ router ในมือถือหรือเครื่องคอมพิวเตอร๋ จะพบชื่อ ESP1

ให้ทำการเรียกใช้ ESP1 ด้วย password 12345678

จากนั้นให้เปิด Browser พิมพ์ 192.168.4.1 ซึ่งจะแสดงปุ่ม Configuration

image

เมื่อกดปุ่ม ก็จะแสดงหน้าข้อมูล ซึ่งสามารถเปลี่ยนข้อมูลและบันทึกได้ และจะกลับไปแสดงหน้าหลัก

image

ถ้าเราปล่อยหน้านี้ค้างไว้เป็นระยะเวลาตามที่กำหนดในตัวแปร AdminTimeOut เมื่อครบกำหนดจะเปลี่ยนจากโหมด AP (Access Point) มาเป็น Station mode ซึ่งต้องได้รับหมายเลข IP จาก router โดย ESP8266 จะใช้ค่าที่เราป้อนไว้ในช่อง SSID และ Password ในการเชื่อมต่อกับ router ถ้าค่าที่เราป้อนให้ไม่ถูกต้องก็จะไม่สามารถเชื่อมต่อกับ router ได้ การสังเกตุการทำงาน ให้เปิด Serial monitor ขณะทำการทดสอบ

เมื่อหมดเวลาที่แสดงคำว่า Admin Mode disabled และทำการเชื่อมต่อ ssid ชื่อ Sae-Ea-Dlink ใช้ password ที่บันทึกไว้

image

ถ้าการเชื่อมต่อกับ router สำเร็จ จะเห็นหมายเลข IP ที่ได้รับ แต่ถ้าไม่สามารถเชื่อมต่อได้ ก็จะเห็นเครื่องหมายจุดแสดงต่อเนื่องกันไป

การจะเข้าสู่โหมด Admin อีกครั้งให้ทำการปลดแหล่งจ่ายไฟสักครู่แล้วต่อเข้าไปใหม่

ค่าที่เก็บตัวอื่น ได้แก่ Private Key, Public Key, Fields ผมสร้างไว้เพื่อเก็บค่าที่ใช้ในการเชื่อมต่อกับ Phant (ผู้อ่านสามารถย้อนกลับไปทบทวนในบล็อกที่ผ่านมาได้

เมื่อต้องการเพิ่มเติม

การพิสูจน์ความเข้าใจในเนื้อหา ทำได้ด้วยการทดลองปรับโน่นเปลี่ยนนี่ แล้วดูผลว่าเป็นไปตามที่เราคิดหรือไม่

ส่วนแรกที่ชี้จุดก็คือ การเพิ่มปุ่มในหน้าแรก เนื้อหาจะอยู่ในไฟล์ Page_Admin.h บรรทัดที่สนใจคือ

<a href="config" style="width:250px" class="btn btn--m btn--blue" >Configuration</a>

คุ้นๆกันนะครับ ก็เป็นการสร้างลิ้งค์นั่นเอง แต่ถ้าเราไม่มีส่วนของ class=”btn btn-m btn-blue” เราก็จะเห็นเพียงข้อความขีดเส้นใต้ ซึ่งก็สามารถทำงานได้เช่นกัน ในส่วนของการตบแต่งด้วย css จะไม่ขอกล่าวนะครับ ถ้าสนใจส่วนนี้ให้ศึกษาเนื้อหาในไฟล์ Page_Style.css.h

ทีนี้ลองเพิ่มปุ่มหนึ่งปุ่ม โดย copy บรรทัดด้านบน เปลี่ยน config เป็น test และ Configuration เป็น Testing

<a href="test" style="width:250px" class="btn btn--m btn--blue" >Testing</a>

ทดลองจะแสดง

image

และเมื่อกดดูจะแสดง Not found: /test เนื่องจาก server ไม่ได้ถูกกำหนดให้บริการ /test ซึ่งจำเป็นต้องไปเพิ่มเติมในไฟล์หลัก

image

ให้มองหาบรรทัด server.on("/config", handleConfig); และเพิ่มบรรทัดนี้ server.on("/test", handleTest);

นอกจากนี้ให้เพิ่มโค๊ดด้านล่างในไฟล์ Page_Config.h หรือสร้างไฟล์ใหม่แล้วบรรจุโค๊ดนี้เข้าไป แต่ต้องไม่ลืม #include ชื่อไฟล์ที่สร้างใหม่นั้นด้วย

void handleTest()
{
  server.send ( 200, "text/plain", "This is a test");
}

จากนั้นทดลองกดปุ่ม Testing คราวนี้จะเห็นประโยคที่เรากำหนดไว้

image

น่าจะพอมองออกนะครับว่า จะต้องเพิ่มอะไรไปบ้าง ในการสร้างปุ่มเมนูเพิ่มเติม

ต่อไปจะมาดูกันว่าเราสามารถจะนำค่าที่ต้องการไปเก็บ จะต้องทำอะไรตรงไหนกันบ้าง

ก่อนอื่นมาดูโครงสร้างของข้อมูลกันก่อน ในไฟล์ globals.h

struct strConfig {
  String ssid;
  String password;
  String DeviceName;
  String IoTPrivateKey;
  String IoTPublicKey;
  String IoTField;
}   config;

การเรียกใช้งานเพื่อเขียนหรืออ่าน จะเรียกตัวแปร config ตามด้วยเครื่องหมายจุด และตามด้วยชื่อสมาชิก เช่น

config.ssid = “ABC”;

และการอ่านค่าไปเก็บไว้ในตัวแปร เช่น

String ssid = config.ssid

เห็นแบบนี้แล้ว ก็ง่ายหละ ถ้าจะเพิ่มก็ทำการเพิ่มตัวแปรเข้าไป หรือไม่ใช้ก็ลบออก

แต่ว่าการเพิ่มการลบ ก็จำเป็นต้องไปเพิ่มหรือลบในตำแหน่งโค๊ดต่างๆ ดังนี้

ในไฟล์หลักที่ตำแหน่ง

if(!ReadConfig())
{
  config.ssid = "ssid";
  config.password = "password";
  config.DeviceName = "ESPNodeRED";
  config.IoTPrivateKey = "123456789";
  config.IoTPublicKey = "abcdef";
  config.IoTField = "f1,f2,f3";
  WriteConfig();
  Serial.println("General config applied");
}

ในไฟล์ Page_Config.h ที่แสดงตัวหนาไว้

void handleConfig()
{
  if(server.args() > 0)
  {
    Serial.println("Save configuration");
    String temp = "";
    for(uint8_t i = 0; i < server.args(); i++)
    {
      if (server.argName(i) == "ssid") config.ssid =   urldecode(server.arg(i));
      if (server.argName(i) == "password") config.password =    urldecode(server.arg(i));
      if (server.argName(i) == "privatekey") config.IoTPrivateKey =    urldecode(server.arg(i));
      if (server.argName(i) == "publickey") config.IoTPublicKey =    urldecode(server.arg(i));
      if (server.argName(i) == "fields") config.IoTField =    urldecode(server.arg(i));
      if (server.argName(i) == "devicename") config.DeviceName =    urldecode(server.arg(i));

    }
    server.send(200,"text/html",WaitAndReload);
    WriteConfig();
  }
  else
  {
    Serial.println("Show table");
    server.send(200, "text/html", Page_Config);
  }
  AdminTimeOutCounter = 0;
  Serial.println(__FUNCTION__);
}

void handleConfigValue()
{

  Serial.println("Retrieve values");
  String values ="";

  values += "ssid|" + (String) config.ssid + "|input\n";
  values += "password|" +  (String) config.password + "|input\n";
  values += "privatekey|" +  (String) config.IoTPrivateKey + "|input\n";
  values += "publickey|" +  (String) config.IoTPublicKey + "|input\n";
  values += "fields|" +  (String) config.IoTField + "|input\n";

  server.send ( 200, "text/plain", values);
  Serial.println(__FUNCTION__);
 
}

และในไฟล์ globals.h

void WriteConfig()
{
  Serial.println("Writing Config");
  EEPROM.write(0, 'N');
  EEPROM.write(1, 'R');
  EEPROM.write(2, '1');

  WriteStringToEEPROM(64, config.ssid);
  WriteStringToEEPROM(96, config.password);
  WriteStringToEEPROM(160, config.IoTPrivateKey);
  WriteStringToEEPROM(192, config.IoTPublicKey);
  WriteStringToEEPROM(224, config.IoTField);
  WriteStringToEEPROM(306, config.DeviceName);

  EEPROM.commit();
}

boolean ReadConfig()
{
  Serial.println("Reading configuration");
  if(EEPROM.read(0) == 'N' && EEPROM.read(1) == 'R' && EEPROM.read(2) == '1')
  {
    Serial.println("Configuration found!");
    config.ssid = ReadStringFromEEPROM(64);
    config.password = ReadStringFromEEPROM(96);
    config.IoTPrivateKey = ReadStringFromEEPROM(160);
    config.IoTPublicKey = ReadStringFromEEPROM(192);
    config.IoTField = ReadStringFromEEPROM(224);
    config.DeviceName = ReadStringFromEEPROM(306);

    return true;
  }
  else
  {
    Serial.println("Configuration NOT FOUND!!!!");
    return false;
  }
}

ทดลองปรับแก้และทดสอบดูกันนะครับ

ส่วนการนำไปใช้งาน ก็ให้นำค่าที่อยู่ในตัวแปร config ไปใช้ ได้ทุกจุดตามต้องการ ซึ่งในส่วนนี้จะนำเอาเนื้อหาในคราวนี้ ไปรวมกับเรื่อง Phant ให้ ESP8266 ทำงานได้แบบที่สามารถปรับเปลี่ยนค่าต่างๆได้ โดยไม่ต้องทำการโค๊ดกันทุกครั้ง จะนำเสนอในคราวต้อไป

สำหรับใครที่ต้องการประยุกต์ไปใช้งาน ต้องวางแนวคิดให้รัดกุมก่อน เพื่อให้การเขียนโค๊ดครั้งเดียว สามารถแปลงร่างให้ ESP8266 ทำงานให้เราได้ตามต้องการ เพียงตั้งค่าให้เหมาะสมเท่านั้น

ไม่มีความคิดเห็น:

แสดงความคิดเห็น