ดิว.นินจา

ดิว.นินจา

Saturday, February 29, 2020

เปลี่ยนผ่านจาก NETPIE 2015 สู่ NETPIE 2020

ผู้ติดตามบล็อกนี้คงทราบดีแล้วว่า NETPIE คือชื่อของบริการคลาวด์สำหรับอุปกรณ์ไอโอทีที่พัฒนาโดยศูนย์อิเล็กทรอนิกส์และคอมพิวเตอร์แห่งชาติ (NECTEC) และปัจจุบันตั้งบริษัท NEXPIE เพื่อสนับสนุนการใช้ในงานอุตสาหกรรมและเชิงพานิชย์ เมื่อวันที่ 20/02/2020 ที่ผ่านมา ได้เปิดตัวแพลตฟอร์มใหม่ในชื่อ NETPIE 2020 ที่แก้ไขข้อจำกัดของเวอร์ชันก่อน (อ้างถึงโดยชื่อ NETPIE 2015) หลายประการ เช่นยกเลิกการใช้ไลบรารี Microgear ที่ยึดติดกับภาษาและฮาร์แวร์ทำให้ขาดความยืดหยุ่น ปรับปรุงให้รองรับโดยฮาร์ดแวร์และภาษาการโปรแกรมหลากหลายมากขึ้น อย่างไรก็ตามการเปลี่ยนแปลงโครงสร้างของ NETPIE 2020 จากเดิมทำให้โปรแกรมเดิมที่ใช้งานอยู่ไม่สามารถใช้ได้และต้องมีการแก้ไข บทความนี้เป็นแนวทางสำหรับผู้พัฒนาบน NETPIE 2015 ที่ต้องการเปลี่ยนผ่านสู่ NETPIE 2020 โดยตั้งสมมุติฐานว่าผู้อ่านมีประสบการณ์หรือความเข้าใจโปรแกรมและการทำงานของเวอร์ชันเก่าอยู่ก่อนแล้ว สำหรับท่านที่ไม่เคยใช้งาน NETPIE มาก่อนเลยแนะนำให้เริ่มต้นจากคู่มือการใช้งานที่ลิงก์ NETPIE 2020 Documentation

หมายเหตุ : ฮาร์ดแวร์ที่ใช้ในบทความนี้คือบอร์ด ESP8266 หรือ ESP32 แบบทั่วไป (เช่น NodeMCU, NodeMCU-32S, ESP32 Dev kit V1) ที่โปรแกรมโดย Arduino IDE เท่านั้น ไม่รวม M5stack, Raspberry Pi หรือฮาร์ดแวร์อื่น ทั้งนี้การที่ NETPIE 2020 ไม่ขึ้นกับไลบรารี Microgear ทำให้โปรแกรมสำหรับ ESP8266 และ ESP32 ไม่แตกต่างกันในมุมของการเชื่อมต่อกับแพลตฟอร์ม เพื่อความง่ายต่อไปจะอ้างอิงอุปกรณ์ฮาร์ดแวร์ว่า NodeMCU

ก่อนอื่นลองมาทบทวนการพัฒนาบนเน็ตพายเวอร์ชันเก่ากันซะหน่อย ขั้นตอนสำคัญในการตั้งค่าและโปรแกรมเพื่อเชื่อมต่ออุปกรณ์ไอโอทีเข้ากับแพลตฟอร์ม NETPIE 2015 มีดังนี้

ด้าน NETPIE 2015

  • ในบัญชีของผู้ใช้ สร้าง Application เป็นเหมือนศูนย์รวมของอุปกรณ์ทั้งหมดที่จะมาต่อในเครือข่ายเดียวกัน ข้อมูลที่ใช้ติดต่อคือชื่อของ Application เรียกว่า APPID
  • สร้าง key สำหรับอุปกรณ์ที่ต่อกับ Application โดยเลือกชนิด device key สำหรับอุปกรณ์ฮาร์ดแวร์ (NodeMCU) และ session key สำหรับอุปกรณ์เชิงลอจิก (เบราเซอร์ Freeboard) ข้อมูลที่ใช้ติดต่อคือ KEY และ SECRET เป็นสตริงอักขระที่สร้างโดยเน็ตพาย อุปกรณ์หลายตัวสามารถใช้ KEY และ SECRET ร่วมกันได้
  • สร้าง session key สำหรับ Freeboard และนำข้อมูล KEY และ SECRET ไปสร้าง datasource
  • ถ้ามีการใช้ FEED สร้าง FEED ในบัญชีผู้ใช้และนำข้อมูล FEEDID, FEEDAPI ไปใช้ด้านอุปกรณ์

ด้าน NodeMCU

(ละเว้นไม่กล่าวถึงส่วนพื้นฐานเช่นการกำหนดขาอินพุต/เอาต์พุต การตั้งค่าพอร์ตอนุกรม ฯลฯ)

บริเวณส่วนหัวของโปรแกรม

  • เรียกไลบรารี WiFi, Microgear และไลบรารีอื่นสำหรับเซนเซอร์ เช่น DHT
  • กำหนดข้อมูล SSID และ password ของ WiFi router ที่ใช้เชื่อมต่ออินเทอร์เน็ต
  • นำข้อมูล APPID, KEY, SECRET จากปัญชี NETPIE มานิยามหรือสร้างเป็นตัวแปรที่ส่วนบนของโปรแกรม
  • ตั้งชื่อ ALIAS ให้กับอุปกรณ์ เพื่อใช้อ้างถึงในคำสั่งการสื่อสาร
  • นิยามชื่อ topic สำหรับพับลิชข้อมูลที่จะรวมกับชื่อ APPID และ ALIAS
  • ถ้าใช้ NETPIE FEED นิยามค่า FEEDID, FEEDAPI
  • สร้าง instance ของออปเจ็ค WiFiClient, Microgear และเซนเซอร์ที่ใช้งาน เช่น DHT
  • นิยามฟังก์ชันต่างๆ ของไลบรารี Microgear เช่น onMsghandler(), onConnected

ในฟังก์ชัน setup()

  • ตั้งค่าเริ่มต้นให้กับเซนเซอร์
  • ตั้งค่าเริ่มต้นให้กับฟังก์ชัน Microgear
  • เชื่อมต่อ WiFi

ในฟังก์ชัน loop()

  • ตรวจสอบการเชื่อมต่อ โดย microgear.connected()
  • ถ้ายังเชื่อมต่ออยู่
    • คงการเชื่อมต่อไว้ โดยเรียก microgear.loop()
    • กำหนดคาบเวลาการอ่านค่าจากเซนเซอร์และพับลิชข้อมูล
    • อ่านค่าจากเซนเซอร์
    • นำค่าจากเซนเซอร์มาสร้างเป็นสตริง ตามรูปแบบที่คั่นด้วยเครื่องหมาย , ระหว่างค่าแต่ละตัว
    • พับลิชข้อมูล ตามชื่อหัวข้อที่ตั้งไว้โดยคำสั่ง microgear.publish()
    • หากมีการใช้ FEED สร้างสตริงสำหรับส่งให้ FEED ตามรูปแบบที่ตั้งไว้ และเขียนไปยัง FEED ตามคาบเวลาที่กำหนดโดยคำสั่ง microgear.writeFeed()
  • ถ้าการเชื่อมต่อหลุด
    • ทำการเชื่อมต่อใหม่ โดย microgear.connect(APPID)

*** สีเหลืองคือส่วนที่ขึ้นกับ NETPIE 2015 และต้องตัดออกหรือแก้ไข ***

Listing 1 ด้านล่างคือตัวอย่างโปรแกรม NodeMCU dhtled_NETPIE15.ino ที่อ่านค่าจากเซนเซอร์ DHT และพับลิชไปยัง NETPIE 2015 ทุก 2 วินาที พร้อมกับเขียนข้อมูลลง FEED ทุก 15 วินาที ในขณะเดียวกันรอรับข้อมูลจากด้านเน็ตพาย หากได้รับข้อมูล 0/1 ก็จะสั่งให้ LED ดับ/ติด เราจะแก้โปรแกรมนี้ให้ทำงานบนแพลตฟอร์ม NETPIE 2020 โค้ดส่วนที่เป็นเหลืองคือคำสั่งที่ใช้กับ NETPIE 2015 และต้องมีการตัดออกหรือแก้ไขเมื่อเปลี่ยนเป็น NETPIE 2020

// dhtled_NETPIE15.ino
// dew.ninja Feb 2020
// connect to NETPIE 2015
// and display temperature, humidity
// also turn on-board OFF/ON  

#include <ESP8266WiFi.h>  // For ESP32, use #include <WiFi.h>
#include <MicroGear.h>    // NETPIE 2015 uses Microgear library

#include "DHT.h"   // library for DHT sensor                          

// ----- WiFi configuration --------------
const char* ssid     = "mywifissid";          
const char* password = "mywifipwd";      

// ******** NETPIE 2015 configuration **********
#define APPID   "dnjcommonApp"
#define KEY     "Ez9K7jzBXx7fzzh"
#define SECRET  "NLGaQYxDV3ukviUkjJFrcQcPVbZiyf"

// ----------- name of this device --------------------
#define ALIAS   "dewIoT"            

// ----- NETPIE 2015 FEED configuration -----
#define FEEDID   "dewGHFeed"           
#define FEEDAPI  "YDAq7tDWmFhLh891qqPjOgVF1eWdl0"          

// ------ topic to publish -----------------------
#define DHTDATATOPIC "/dhtlight/" ALIAS            
// **************************************************


#define DHTPIN    D1          
#define DHTTYPE   DHT11       // e.g. DHT11, DHT21, DHT22
DHT dht(DHTPIN, DHTTYPE);
#define LED1 LED_BUILTIN     // use on-board LED

float humidity = 0;     
float temperature  = 0;     

unsigned long lastDHTRead = 0, newDHTRead=0;
unsigned long lastTimeWriteFeed = 0, newTimeWriteFeed = 0;

WiFiClient client;

// ***** NETPIE 2015 Microgear instance and function declarations ******
MicroGear microgear(client);
void onMsghandler(char *topic, uint8_t* msg, unsigned int msglen) {
    Serial.print("Incoming message --> ");
    msg[msglen] = '\0';
    Serial.println((char *)msg);

    if (*(char *)msg == '0') digitalWrite(LED1,0);
    else if (*(char *)msg == '1') digitalWrite(LED1,1);
}

void onConnected(char *attribute, uint8_t* msg, unsigned int msglen) {
    Serial.println("Connected to NETPIE...");
    microgear.setAlias(ALIAS);
}
// **************************************************************


void setup() {
    pinMode(LED_BUILTIN, OUTPUT);
    Serial.begin(115200);
    dht.begin(); // initialize DHT module
    if (WiFi.begin(ssid, password)) {
        while (WiFi.status() != WL_CONNECTED) {
            delay(1000);
            Serial.print(".");
        }
    }
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    
    // ************** Microgear initialization ****************
    microgear.on(MESSAGE,onMsghandler);
    microgear.on(CONNECTED,onConnected);
    microgear.init(KEY,SECRET,ALIAS);   
    microgear.connect(APPID);           
    // ***************************************************
}

void loop() {
 
    if (microgear.connected()) {
        microgear.loop(); 

        newDHTRead = millis();
        if(newDHTRead - lastDHTRead > 2000)  {
          humidity = dht.readHumidity();     // read humidity
          temperature  = dht.readTemperature();  // read temperature
          lastDHTRead = newDHTRead;

          // check if data is valid 
          if (isnan(humidity) || isnan(temperature)) {
            humidity=0;
            temperature=0;
            Serial.println("Failed to read from DHT sensor!");
          }
          else{
            
            String datastring = (String)humidity+","+(String)temperature;
            Serial.print("Sending --> ");
            Serial.println(datastring);
            microgear.publish(DHTDATATOPIC,datastring);   

          }
        }
        
        // ******** NETPIE 2015 FEED write ****************
        newTimeWriteFeed = millis();
        if(newTimeWriteFeed-lastTimeWriteFeed > 15000){
          lastTimeWriteFeed = newTimeWriteFeed;
          if(humidity!=0 && temperature!=0){
            String feeddata = "{\"humid\":";
            feeddata += humidity ;
            feeddata += ", \"temp\":";
            feeddata += temperature;
            feeddata += "}"; 
            Serial.print("Write Feed --> ");
            Serial.println(feeddata);
            //microgear.writeFeed(FEEDID,feeddata);
            microgear.writeFeed(FEEDID,feeddata,FEEDAPI);
          }
        }
        // ************************************************ 
    }   
    else { 
        Serial.println("connection lost, reconnect...");
        microgear.connect(APPID); 
    }
    delay(100);
}

Listing 1 dhtled_NETPIE15.ino โปรแกรม NodeMCU ที่ใช้เชื่อมต่อกับ NETPIE 2015

การเปลี่ยนแปลงจะอาศัยแนวทางตามตัวอย่างในลิงก์ของ NETPIE https://netpie.io/tutorials/NodeMCU สามารถสรุปได้ดังนี้

  • เลิกใช้ไลบรารี Microgear.h เปลี่ยนเป็นไลบรารี PubSubClient.h
  • เลิกใช้ข้อมูล APPID, KEY, SECRET เปลี่ยนเป็นข้อมูล Client ID, Token (Username), Secret จาก NETPIE 2020
  • มีส่วนที่เพิ่มมาคือชื่อ MQTT server (broker.netpie.io) และพอร์ต (1883)
  • ไม่ต้องตั้งชื่อ ALIAS ให้กับอุปกรณ์
  • เนื่องจากไม่มีการสร้าง instance ของออปเจ็ค Microgear แล้ว ดังนั้นฟังก์ชันที่เกี่ยวข้องจะลบทิ้งทั้งหมด เปลี่ยนเป็นการเชื่อมต่อในรูปแบบใหม่ที่จะกล่าวถึงต่อไป
  • NETPIE 2020 ไม่มี FEED แต่จะยังสนับสนุนการเขียนข้อมูลฐานเวลาที่กำหนดโดย Device Schema
  • การตั้งค่าเซนเซอร์และเชื่อมต่อ WiFi ยังคงใช้คำสั่งเดิม
  • การอ่านค่าจากเซนเซอร์ยังคงใช้คำสั่งเดิม

ต่อไปจะอธิบายขั้นตอนในการตั้งค่าและโปรแกรมเพื่อเชื่อมต่อ NodeMCU เข้ากับแพลตฟอร์ม NETPIE 2020

ด้าน NETPIE 2020

  • Login เข้าสู่หน้า portal
  • สร้าง project ใหม่
  • บนแท็บ Device List สร้าง device สำหรับ NodeMCU จะเห็นว่า NETPIE 2020 สร้างข้อมูล Client ID, Token, Secret ให้เพื่อที่เราจะนำมาใช้ในโปรแกรม

ก่อนที่จะสร้าง Freeboard ควรตรวจสอบจากด้านล่างของ device ในหน้าต่าง [Shadow] ว่าข้อมูลถูกส่งมาถูกต้องหรือไม่

ด้าน NodeMCU

เราจะแก้ไขโปรแกรม dthled_NETPIE15.ino โดยเซฟไฟล์เป็นชื่อ dhtled_NETPIE20.ino และแก้ไขจากด้านบนลงมา โดยจะใช้อักขระ ---xxx--- ใส่เพิ่มในส่วนหน้าของที่คอมเมนต์ออกด้วย

หมายเหตุ : ที่แนะนำให้ใช้การคอมเม้นต์แทนการลบโค้ดออกโดยถาวร เพราะผู้เริ่มต้นอาจจะพลาดลบเอาโค้ดส่วนที่จำเป็นต้องใช้ออกไป ซึ่งสามารถจะนำกลับคืนมาได้หากพบว่าโปรแกรมทำงานไม่ถูกต้องโดยปลดคอมเม้นต์ บนเมนู Edit ของ Arduino IDE มีตัวเลือก Comment/Uncomment ที่ทำงานในลักษณะสลับสถานะ

เริ่มจากการเรียกไลบรารี คอมเม้นต์ Microgear.h ออก


// ---xxx--- #include <MicroGear.h>    // NETPIE 2015 uses Microgear library 
และใส่ PubSubClient.h เข้าไปแทน

#include "PubSubClient.h"        // library for NETPIE 2020 communication 

ส่วนการนิยาม WiFi คงไว้เหมือนเดิม ต่อมาคอมเม้นต์ส่วนตั้งค่าสำหรับ NETPIE 2015 ออกไปทั้งหมด


//// ******** NETPIE 2015 configuration **********
//---xxx--- #define APPID   "dnjcommonApp"
//---xxx---#define KEY     "Ez9K7jzBXx7fzzh"
//---xxx---#define SECRET  "NLGaQYxDV3ukviUkjJFrcQcPVbZiyf"
//
//// ----------- name of this device --------------------
//---xxx---#define ALIAS   "dewIoT"            
//
//// ----- NETPIE 2015 FEED configuration -----
//---xxx---#define FEEDID   "dewGHFeed"           
//---xxx---#define FEEDAPI  "YDAq7tDWmFhLh891qqPjOgVF1eWdl0"          
//
//// ------ topic to publish -----------------------
//---xxx---#define DHTDATATOPIC "/dhtlight/" ALIAS            
//// **************************************************

และใส่การตั้งค่าสำหรับ NETPIE 2020 เข้าไปแทน


// ^^^^^^^^^^^^^^ NETPIE 2020 configuration ^^^^^^^^^^^^^^^^^^
const char* mqtt_server = "broker.netpie.io";
const int mqtt_port = 1883;
const char* mqtt_Client = "772e64d-0458-4849-9086-756db53bc2";
const char* mqtt_username = "w16i6Fz4SGtiYqfL2UkxBK9BGWsC4";
const char* mqtt_password = "@OS&ve76I1^S%$45UR!6C~bx~e3k#";
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

ลบคำสั่ง


WiFiClient client; 

ออก เปลี่ยนเป็นสร้าง instance ของ WiFiClient และ PubSubClient ตามคำสั่งดังนี้


WiFiClient espClient;
PubSubClient client(espClient); 

คอมเม้นต์ในส่วนการสร้าง instance และการนิยามฟังก์ชันของไลบรารี Microgear ออกทั้งหมด (ถ้าในโปรแกรมมีฟังก์ชันอื่นที่เกี่ยวข้องกับ Microgear ให้คอมเม้นต์ออกด้วย)


//// ***** NETPIE 2015 Microgear instance and function declarations ******
// ---***--- MicroGear microgear(client);
// ---***--- void onMsghandler(char *topic, uint8_t* msg, unsigned int msglen) {
// ---***---     Serial.print("Incoming message --> ");
// ---***---     msg[msglen] = '\0';
// ---***---     Serial.println((char *)msg);
//
// ---***---     if (*(char *)msg == '0') digitalWrite(LED1,0);
// ---***---     else if (*(char *)msg == '1') digitalWrite(LED1,1);
// ---***--- }
//
// ---***--- void onConnected(char *attribute, uint8_t* msg, unsigned int msglen) {
// ---***---     Serial.println("Connected to NETPIE...");
// ---***---     microgear.setAlias(ALIAS);
// ---***--- }
//// **************************************************************

แทนที่ด้วยนิยามของฟังก์ชัน reconnect() ที่ใช้สำหรับเชื่อมต่อกับ NETPIE 2020


void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection…");
    if (client.connect(mqtt_Client, mqtt_username, mqtt_password)) {
      Serial.println("connected");
      client.subscribe("@msg/led");
    }
    else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println("try again in 5 seconds");
      delay(5000);
    }
  }
}

และฟังก์ชัน callback() ทำหน้าที่รับข้อความที่ส่งมายังอุปกรณ์นี้


void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  String message;
  for (int i = 0; i < length; i++) {
    message = message + (char)payload[i];
  }
  Serial.println(message);

  if(String(topic) == "@msg/led") {
    if (message == "on"){
      digitalWrite(LED1,0);
      client.publish("@shadow/data/update", "{\"data\" : {\"led\" : \"on\"}}");
      Serial.println("LED ON");
    }
    else if (message == "off") {
      digitalWrite(LED1,1);
      client.publish("@shadow/data/update", "{\"data\" : {\"led\" : \"off\"}}");
      Serial.println("LED OFF");
    }
  }
}

โดยในฟังก์ชันนี้จะรับคำสั่งที่ส่งมาจาก Freeboard และปิด/เปิด LED บน NodeMCU ด้วย คำอธิบายอ่านได้จากตัวอย่างในลิงก์ https://netpie.io/tutorials/NodeMCU

ในส่วนของฟังก์ชัน setup() โค้ดที่เกี่ยวข้องกับการกำหนดขา การตั้งค่าของพอร์ตอนุกรม เซนเซอร์ และการเชื่อมต่อ WiFi จะไม่มีการเปลี่ยนแปลงใดๆ ส่วนที่เปลี่ยนคือคอมเม้นต์ส่วนการตั้งค่า microgear ออก


//    // ************** Microgear initialization ****************
// ---***---     microgear.on(MESSAGE,onMsghandler);
// ---***---     microgear.on(CONNECTED,onConnected);
// ---***---     microgear.init(KEY,SECRET,ALIAS);   
// ---***---     microgear.connect(APPID);           
//    // ***************************************************

แทนด้วยการตั้งค่าสำหรับ NETPIE 2020 ซึ่งมีเพียง 2 บรรทัดเท่านั้น


// ^^^^^^^^^^^^^ initialization for NETPIE 2020 ^^^^^^^^^^^^^^^^^
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

สำหรับในส่วนของฟังก์ชัน loop() เนื่องจากเราใช้ออปเจ็ค client ของไลบรารี PubSubClient แทนออปเจ็คของไลบรารี microgear จึงคอมเม้นต์ในส่วนต้นที่มีเงื่อนไข


// ---xxx---    if (microgear.connected()) {
// ---xxx---       microgear.loop();

ออก และเพิ่มเติมเงื่อนไขใหม่เป็น


    if (client.connected()) {
        client.loop();

โดยจะเห็นว่ามีลักษณะการทำงานคล้ายกัน คือตรวจสอบว่าหากยังมีการเชื่อมต่ออยู่จะต้องเรียกเมธอด loop() เพื่อรักษาการเชื่อมต่อไว้

เลื่อนลงมาในส่วนของ else เมื่อเงื่อนไขไม่เป็นจริง คือพบว่าการเชื่อมต่อหลุดจะต้องทำคำสั่งเชื่อมต่อใหม่ คอมเม้นต์ของเดิมที่ใช้ microgear ออก


// ---xxx---    else {
// ---xxx---        Serial.println("connection lost, reconnect...");
// ---xxx---        microgear.connect(APPID); 
// ---xxx---    }

และเปลี่ยนเป็น


    else   {
      reconnect();
    }

ซึ่งจะไปเรียกฟังก์ชัน reconnect() ที่นิยามไว้ด้านบน

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


// ---xxx---            String datastring = (String)humidity+","+(String)temperature;
// ---xxx---            Serial.print("Sending --> ");
// ---xxx---            Serial.println(datastring);
// ---xxx---            microgear.publish(DHTDATATOPIC,datastring);

แทนที่ด้วยการจัดรูปแบบสตริงแบบ JSON ที่ใช้ใน NETPIE 2020


    String data = "{\"data\": {\"humidity\":" + String(humidity) + 
 ", \"temperature\":" + String(temperature) + 
 ", \"place\": \"" +  String(place) + "\"}}";
    Serial.println(data);
    data.toCharArray(msg, (data.length() + 1));
    client.publish("@shadow/data/update", msg);

ตัวแปร place แบบสตริงถูกเพิ่มที่หัวของโปรแกรมโดยเป็นค่าคงที่ "NECTEC Thailand" เพื่อเป็นการทดสอบการส่งค่าแบบสตริง ชื่อของ topic ที่พับลิชให้กับ NETPIE 2020 จะเป็น"@shadow/data/update" เสมอ

สังเกตว่าใน NETPIE 2020 เราไม่สามารถพับลิชข้อมูลที่เป็นตัวแปรสตริง คือ data ไปได้โดยตรง แต่ต้องแปลงให้เป็นตัวแปรแบบ character array ก่อน ดังนั้นที่ส่วนบนของโปรแกรมต้องเพิ่มนิยามตัวแปร msg ดังนี้


char msg[100];

โดยมีขนาดไม่น้อยไปกว่าจำนวนอักขระในสตริงที่ต้องการพับลิช

ส่วนสุดท้ายที่ต้องคอมเมนต์ออกไปคือการเขียน FEED เนื่องจาก NETPIE 2020 ไม่มีส่วนของ FEED แล้ว


//        // ******** NETPIE 2015 FEED write ****************
// ---xxx---        newTimeWriteFeed = millis();
// ---xxx---        if(newTimeWriteFeed-lastTimeWriteFeed > 15000){
// ---xxx---          lastTimeWriteFeed = newTimeWriteFeed;
// ---xxx---          if(humidity!=0 && temperature!=0){
// ---xxx---            String feeddata = "{\"humid\":";
// ---xxx---            feeddata += humidity ;
// ---xxx---            feeddata += ", \"temp\":";
// ---xxx---            feeddata += temperature;
// ---xxx---            feeddata += "}"; 
// ---xxx---            Serial.print("Write Feed --> ");
// ---xxx---            Serial.println(feeddata);
// ---xxx---            //microgear.writeFeed(FEEDID,feeddata);
// ---xxx---            microgear.writeFeed(FEEDID,feeddata,FEEDAPI);
// ---xxx---          }
// ---xxx---        }
//        // ************************************************

เมื่อคอมไพล์และโหลดโปรแกรม dhtled_NETPIE20.ino ลงบน NodeMCU เปิด Serial Monitor จะเห็นสตริงที่พับลิชให้กับ NETPIE 2020 ดังแสดงในรูปที่ 1

รูปที่ 1 สตริงข้อมูลในรูปแบบ JSON ที่พับลิชไปยัง NETPIE 2020

Device Schema

ดังได้กล่าวแล้วว่า NETPIE 2020 จะไม่มีหน้า FEED สำหรับเก็บข้อมูลแยกต่างหาก การแสดงผลและเก็บข้อมูลฐานเวลาจะรวมอยู่ในที่เดียวกัน และอาศัยโค้ดที่กำหนดรูปแบบการจัดเก็บข้อมูลเรียกว่า Device Schema ที่อยู่ในรูปแบบ JSON รายละเอียดอ่านได้จากลิงก์ https://docs.netpie.io/device-config.html

ในหน้า portal ของ NETPIE 2020 เลือก device ที่เชื่อมต่ออยู่กับ NodeMCU และคลิกที่ปุ่ม [Schema] เลือกการป้อนข้อมูลแบบ Code ตัวอย่างนี้จะใช้โค้ดใน Listing 2 ที่ได้จาก NETPIE 2020 Workshop โดยสามารถใส่การคำนวณขั้นพื้นฐานลงในโค้ดได้ เช่นแปลงหน่วยของอุณหภูมิจากเซลเซียสเป็นฟาร์เรนไฮต์


{
  "additionalProperties": false,
  "properties": {
    "humidity": {
      "operation": {
        "store": {
          "ttl": "7d"
        }
      },
      "type": "number"
    },
    "temperature": {
      "operation": {
        "store": {
          "ttl": "7d"
        },
        "transform": {
          "expression": "(($.temperature)*1.8) + 32"
        }
      },
      "type": "number"
    },
    "place": {
      "operation": {
        "store": {
          "ttl": "7d"
        }
      },
      "type": "string"
    },
    "led": {
      "operation": {
        "store": {
          "ttl": "7d"
        }
      },
      "type": "string"
    }
  }
}

Listing 2 Schema code สำหรับตัวอย่างในบทความ

เมื่อคลิกที่ปุ่ม [Shadow] จะเห็นว่า NETPIE 2020 ได้รับข้อมูลที่ส่งมาจาก NodeMCU ดังในรูปที่ 2

รูปที่ 2 ข้อมูลจาก NodeMCU ที่พับลิชให้กับ NETPIE 2020

มาถึงขั้นนี้โปรแกรมด้าน NodeMCU ได้ถูกแก้ไขให้ใช้งานได้กับ NETPIE 2020 แล้ว สำหรับการสร้าง Freeboard ได้ถูกอธิบายไว้อย่างละเอียดแล้วในลิงก์ https://netpie.io/tutorials/NodeMCU ดังนั้นจึงจะไม่กล่าวถึงในที่นี้ รูปที่ 3 แสดงหน้า Freeboard ที่สร้างขึ้นและใช้งานได้ตามวัตถุประสงค์

รูปที่ 3 หน้า Freeboard ที่ใช้กับโปรแกรมในบทความนี้

สำหรับท่านที่ต้องการรันตัวอย่างโปรแกรมนี้บน ESP32 ทำได้โดยง่าย แก้ไขเพียงไลบรารี WiFi ที่ส่วนหัวของโปรแกรม โดยเปลี่ยนจาก


#include <ESP8266WiFi.h> 

เป็นไลบรารีที่ใช้สำหรับ ESP32 ดังนี้


#include <WiFi.h> 

และกำหนดขาที่ต่อกับเอาต์พุตของเซนเซอร์ DHT ให้ตรงกับที่ใช้จริง เช่น


#define DHTPIN 16

ในรูปที่ 4 ผู้เขียนได้ใช้บอร์ด ESP32 Dev Kit V1 ที่หาได้ทั่วไป ต่อเซนเซอร์ DHT22 เข้ากับขา 16 พบว่าใช้งานได้เหมือนกับ NodeMCU ทุกประการ (ถ้าใช้ DHT22 อย่าลิมแก้นิยาม DHTTYPE ให้ตรงกันด้วย ไม่งั้นค่าจะอ่านได้ผิดพลาด)

รูปที่ 4 การทดสอบโปรแกรมบน ESP32

รวมโปรแกรมในบทความ dhtled.zip

No comments:

Post a Comment

แนะนำหนังสือ “ตัวควบคุมป้อนกลับบนอินเทอร์เน็ตโดย ESP8266”

ปัจจุบันเมื่อกล่าวถึงอุปกรณ์ IoT (Internet of Things) คงมีน้อยคนที่จะไม่รู้จัก ในยุคที่การเข้าถึงอินเทอร์เน็ตเป็นกิจวัตรประจำวันของมนุษย์เ...