การรีเซ็ตโหนด mcu esp 8266 แบบตั้งเวลาให้ Reset อัตโนมัติแทนการกดปุ่มที่บอร์ด แบบไม่ง้อ Code

สวัสดีครับทุกท่านสำหรับวันนี้นะครับผมก็จะนำเสนอไอเดียเกี่ยวกับเรื่องของ การรีเซ็ตบอร์ดของ node mcu esp 8266 โดยไม่ต้องใช้คำสั่ง ESP.reset() หรือ ESP.restart() เพราะการทำวิธีนี้ผมลองศึกษาดูแล้วปรากฏว่าเมื่อใช้คำสั่งนี้ เมื่อถึงเวลาที่เราตั้งค่าเอาไว้เราจะต้องมีการกดปุ่มรีเซ็ตแบบ Manual ที่บอร์ด 1 ครั้ง จากนั้นเมื่อครบรอบเวลาครั้งต่อไปมันจะทำการรีเซ็ต บอร์ดของ node mcu esp 8266 ให้แบบอัตโนมัติ แต่ปัญหามันติดอยู่ที่ว่าถ้าเราต้องการตั้งเวลาไป 15 ชั่วโมงเราต้องรอเวลาให้ครบ 15 ชั่วโมงก่อนแล้วจึงมากดปุ่มรีเซ็ต เพื่อให้รอบต่อไปในการทำงานเป็นแบบอัตโนมัติ

จากสาเหตุดังกล่าวผมจึงคิดวิธีการว่าผมเพียงแค่ต้องการที่จะตั้งเวลาเอาไว้และเมื่อถึงเวลาก็ให้มัน Reset บอร์ดของ node mcu esp 8266เลยโดยไม่ต้องใช้คำสั่ง ESP.reset() หรือ ESP.restart() และไม่ต้องไปกดปุ่มรีเซ็ตบอร์ด ในครั้งแรก ดังนั้นแนวคิดของผมคือทำอย่างไรให้เราไม่ต้องไปกดปุ่ม Reset บอร์ดในครั้งแรก ดังนั้นจึงเกิดเป็นแนวคิด โดยการใช้ทรานซิสเตอร์เข้ามาช่วย เพื่อจะทำให้การทำงานเป็นแบบอัตโนมัติเหมือนกดปุ่ม Reset บอร์ดจริงๆ ยังไงเดี๋ยวลองชมคลิปผลลัพธ์ที่ได้ก่อนนะครับ

จากที่ได้อธิบายไปก็เขียนได้ diagram ได้ตามนี้ ในส่วนของตัวโค้ชนั้นผมจะนำเสนอเป็นบางส่วนเพื่อให้นำไปศึกษาการใช้งานดูนะครับ ในส่วนของ Push button switch อาจจะต่อหรือไม่ต่อก็ได้แต่ถ้าต่อก็แนะนำให้ใช้โค้ดที่ผมลงในบทความก่อนๆดูนะครับ

#define D5 14

void setup() {
  pinMode(D5, OUTPUT);
  digitalWrite(D5, HIGH);//ให้ D5 เป็น 0

}

void loop() {
  delay(10000);
  digitalWrite(D5, LOW);//ให้ D5 เป็น 1
}

มีแค่นี้ครับ อิ..อิ… เอาไว้ทดลองว่าได้ผลหรือไม่ แต่จริงๆแล้วมันได้ผลครับ ผมรับประกัน เพราะผมต้องการเอาไปใช้งานจริง ไม่ได้ทำไว้ทดลองครับ
ที่นี้การเขียนโค้ดง่ายๆแบบนี้มันก็ไม่มีปัญหาใช่ไหมครับ แต่ถ้าเกิดว่าเรามีโค้ดยาวๆขึ้นมา การหน่วงเวลาที่ 10 วินาทีจะทำให้โปรแกรมเกิดการหน่วงเวลา ซึ่งจะทำให้ โค้ดตัวอื่นๆไม่สามารถจะทำงานได้เลย ดังนั้นเราจึงจำเป็นที่จะต้องให้ Node MCU Esp 8266 ทำงานแบบ Multi Task นั่นเอง เพื่อไม่ทำให้เกิดการหน่วงของ code ที่ใช้กับอุปกรณ์ตัวอื่น
ตัวอย่าง Code ครับ

//*********************************************************************************************
//NodeMCU V2 จะมี LED อยู่ 2 ตัวคือบนชิพ ESP8266 (D4) และบนบอร์ด (D0)
//NodeMCU V3 จะมี LED อยู่ 1 ตัวคือบนชิพ ESP8266 (D4) ซึ่งไม่มีบนบอร์ดเหมือน V2
//เลือกบอร์ดเป็น NodeMCU 1.0 ความเร็วอัพโหลดจะเป็น 115200 และ LED_BUILTIN จะเป็น D0
//*********************************************************************************************

#include <ESP8266WiFi.h>                  //โหลดไลบารี่ ..มาใช้งาน                        //https://github.com/esp8266/Arduino
#include <ESP8266WebServer.h>             //โหลดไลบารี่ ..มาใช้งาน
#include <WiFiManager.h>                  //โหลดไลบารี่ ..มาใช้งาน                        //https://github.com/tzapu/WiFiManager
#include <FS.h>                           //โหลดไลบารี่ ..มาใช้งาน                        //this needs to be first, or it all crashes and burns...
#include <DNSServer.h>                    //โหลดไลบารี่ ..มาใช้งาน
#include <ArduinoJson.h>                  //โหลดไลบารี่ ..มาใช้งาน                        //https://github.com/bblanchon/ArduinoJson
#include <BlynkSimpleEsp8266.h>           //โหลดไลบรารี่ของ BLYNK ..มาใช้งาน

#include <time.h>//NTP Server

#include <Scheduler.h>

#include <LCD.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
//------------ LCD ---------------------------
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

byte Wifibase[8] = //icon for termometer
{
  B11111,
  B10101,
  B10101,
  B01110,
  B00100,
  B00100,
  B00100,
  B00100
};
byte WifiL1[8] = //icon for termometer
{
  B00110,
  B00110,
  B00110,
  B00110,
  B00110,
  B00110,
  B00110,
  B00110
};

byte WifiL2[8] = //icon for termometer
{
  B01110,
  B01110,
  B01110,
  B01110,
  B01110,
  B01110,
  B01110,
  B01110
};


byte WifiL3[8] = //icon for termometer
{
  B11110,
  B11110,
  B11110,
  B11110,
  B11110,
  B11110,
  B11110,
  B11110
};

byte intrnetok[8] = //icon for termometer
{
  B01110,
  B10101,
  B10101,
  B10101,
  B10101,
  B10101,
  B01110,
  B00100
};




byte blynk[8] = //icon for termometer
{
  B01110,
  B10101,
  B10101,
  B10101,
  B10101,
  B10101,
  B01110,
  B00100
};

#include "PCF8574.h"
PCF8574 pcf8574_3(0x3C);//ตัวที่ 3
PCF8574 pcf8574_2(0x3A); //ตัวที่ 2
PCF8574 pcf8574_1(0x38); //ตัวที่ 1
unsigned long timeElapsed;


#define BLYNK_DEBUG
#define BLYNK_PRINT Serial        // Comment this out to disable prints and save space
#define D0 16                     // ใช้ไฟ LED สีฟ้า ของบอร์ด MCU ESP8266 ให้มีสัญญาณไฟกระพริบ ตาม Code ที่เขียน
#define D3 0                     // ใช้เป็นปุ่มกด เพื่อเข้า AP Config ได้ตามความต้องการของผู้ใช้

#define D7 13                     //เชคสัญญาณ Internet เชคระดับสัญญาณ WiFi

#define D4 2                     //เชคระดับสัญญาณ WiFi 0-30%
#define D5 14                    //เชคระดับสัญญาณ WiFi >=50%
#define D6 12                    //เชคระดับสัญญาณ WiFi >=60%


#define D9 3


//------------------------------------------------------------------------------------------------
long rssi;
int rssiled;
//------------------------------------------------------------------------------------------------


//LED แสดงสถานะ Internet โดยแนวคิดคือ วนลูป loop ให้ ESP8266 ติดต่อ www.google.co.th ไปเรื่อยๆ LED ก็จะติด แสดงว่า Internet มา
const char* host = "www.google.co.th";    //ต้องการให้ส่งการติดต่อไปยัง Website นี้


//-------------------------------------------------------------------------------------------------------------------------------------------

int blynkIsDownCount = 0;                                     //Integer Variable ตัวแปรชื่อ blynkIsDownCount ใช้เก็บเลขจำนวนเต็ม โดยเริ่มต้นให้มีค่า = 0
char blynk_token[34] = "OUoATnGCDD229TqtcE6PVW6Yewp8feTr";    //ใส่ Blynk token ของเราที่ Blynk ส่งมาทาง Email ตอนที่เรา Create Project ใหม่
//Character Variable ตัวแปรที่ใช้เก็บอักขระ
bool shouldSaveConfig = false;

//-------------------------------------------------------------------------------------------------------------------------------------------

BlynkTimer timer;  //เรียกใช้การตั้งเวลาของ Blynk
//ฟังชั่นเปิดใช้งาน BlynkTimer ซึ่งทำหน้าที่คล้าย ๆ interrupt timer หมายถึงเมื่อครบเวลาตามที่กำหนดไว้โปรแกรมหลักจะกระโดด
//ไปทำงานในโปรแกรมตอบสนองที่กำหนดไว้
//กรณีนี้จะนำฟังชั่นที่เปิดใช้งาน BlynkTimer ไปใช้ในการ เชื่อมต่อซ้ำ (reconnecting)
//โดยรูปแบบคำสั่ง คือ timer.setInterval(30000L, reconnecting); อยู่ใน void setup

//-------------------------------------------------------------------------------------------------------------------------------------------


//callback notifying us of the need to save config
void saveConfigCallback () {
  Serial.println("Should save config");
  shouldSaveConfig = true;
}
//-------------------------------------------------------------------------------------------------------------------------------------------


//***********สำหรับ Server local ที่แจกให้ เพิ่ม **** แค่ 2 บรรทัดนี้
char server[] = "oasiskit.com";
int port = 8080;
//***************************************************************


int timezone = 7;

char ntp_server1[20] = "ntp.ku.ac.th";
char ntp_server2[20] = "fw.eng.ku.ac.th";
char ntp_server3[20] = "time.uni.net.th";

int dst = 0;


class RssiTask : public Task {
  protected:
    void loop()  {
      rssi = WiFi.RSSI();
      rssiled = ((((rssi * 100) / -127) - 100) * -1);// ทำให้เป็น % ความแรงของ WiFi จะดูง่ายกว่า
      //Blynk.virtualWrite(V5, ( ((rssi * 100) / -127) - 100) * -1);   // ทำให้เป็น % ความแรงของ WiFi จะดูง่ายกว่า

      //เชคระดับสัญญาณ WiFi >= 60%
      if (rssiled >= 60  ) {
        digitalWrite(D6, HIGH);
        lcd.setCursor(0, 0);
        lcd.write(3);
        delay(10);

      } else  {
        digitalWrite(D6, LOW);
        lcd.setCursor(0, 0);
        lcd.print((char)0x20);//ว่าง ไม่มีสี
        delay(10);

      }
      //เชคระดับสัญญาณ WiFi >= 50%
      if (rssiled >= 50  ) {
        digitalWrite(D5, HIGH);
        lcd.setCursor(0, 1);
        lcd.write(2);
        delay(10);

      } else  {
        digitalWrite(D5, LOW);
        lcd.setCursor(0, 1);
        lcd.print((char)0x20);
        delay(10);

      }
      //เชคระดับสัญญาณ WiFi 0-30%
      if (rssiled >= 30  ) {
        digitalWrite(D4, HIGH);
        lcd.setCursor(0, 2);
        lcd.write(1);
        delay(10);

      } else  {
        digitalWrite(D4, LOW);
        lcd.setCursor(0, 2);
        lcd.print((char)0x20);
        delay(10);

      }

      yield();
      delay(200);
    }

} rssi_print_task;




//----------------------------------------------------------------------------------------------------------------------------

class InternetTask : public Task {
  protected:
    void loop()  {

      //----------------------------------------------------------------------------------------------------------------------------
      //เพื่อป้องกันไม่ให้ มีการติดต่อ ถี่เกินไป จะกำหนดให้ วน loop ปกติเป็นจำนวน n ครั้ง ตัวอย่าง i=100 จะวน 100 รอบปกติก่อน แล้วจึงมาที่  WiFiClient client; 1 ครั้ง
      //Client เป็นการกำหนดให้ ESP8266 ทำหน้าที่เป็นเครื่องลูกข่าย โดยเชื่อมต่อไปยังเครื่องแม่ข่ายด้วยไอพีแอดเดรสและพอร์ตที่กำหนดไว้เพื่อขอใช้บริการนั้นๆ
      //WiFiClient(); คือ การประกาศสร้าง object ของ WifiClient
      //เป็นฟังก์ชั่นสำหรับสั่งให้ ESP8266 เชื่อมต่อกับ Server ด้วย URL และ Port
      //host = สำหรับกำหนด URL ของ Server ที่ต้องการเชื่อมต่อ host
      //port = สำหรับกำหนด Port ที่ Server เปิดรับอยู่ 80

      WiFiClient client;
      if (client.connect(host, 80))
      {
        //Serial.println("connected");
        digitalWrite(D7, HIGH);
        client.stop();
        delay(100);

        lcd.setCursor(11, 3);
        lcd.write(5);
      }
      else {
        //Serial.println("connection failed!");
        digitalWrite(D7, LOW);
        client.stop();

        lcd.setCursor(11, 3);
        lcd.print((char)0x20);
      }

      delay(4000);
    }
} internet_print_task;

//----------------------------------------------------------------------------------------------------------------------------

class BlynkTask : public Task {
  protected:
    void loop()  {

      //--------------------------------------------------------------------------------------------------------
      if (Blynk.connected())
      {
        Blynk.run();

        digitalWrite(D0, HIGH);

        lcd.setCursor(19, 3);
        lcd.write(6);



      } else {

        digitalWrite(D0, LOW);

        lcd.setCursor(19, 3);
        lcd.print((char)0x20);
        delay(200);

        digitalWrite(D0, HIGH);

        lcd.setCursor(19, 3);
        lcd.write(6);

        delay(100);

      }
      //--------------------------------------------------------------------------------------------------------


      timer.run();//ให้เวลาของ Blynk ทำงาน

      delay(100);

    }
} blynk_task;

//----------------------------------------------------------------------------------------------------------------------------



class DMTTask : public Task {
  protected:
    void setup() {

      configTime(timezone * 3600, dst, ntp_server1, ntp_server2, ntp_server3);
      //Serial.println("Waiting for time");
      while (!time(nullptr)) {
        //Serial.print(".");
        delay(500);
      }
      //Serial.println();
      //Serial.println("Now: " + NowString());


    }

    void loop() {
      lcd.setCursor(0, 0);
      lcd.print(NowString());

      lcd.setCursor(10, 0);
      lcd.print(NowString2());

      delay(1000);
    }



    //NTP SERVER
    String NowString() {
      time_t now = time(nullptr);
      struct tm* newtime = localtime(&now);

      String tmpNow = "";
      tmpNow += " ";
      tmpNow += String(newtime->tm_hour);
      tmpNow += ":";
      tmpNow += String(newtime->tm_min);
      tmpNow += ":";
      tmpNow += String(newtime->tm_sec);
      return tmpNow;
    }

    String NowString2() {
      time_t now = time(nullptr);
      struct tm* newtime = localtime(&now);

      String tmpNow = "";
      tmpNow += String(newtime->tm_mday);

      tmpNow += "-";
      tmpNow += String(newtime->tm_mon + 1);
      tmpNow += "-";
      tmpNow += String(newtime->tm_year + 2443);//+ อีก 2443 จะได้เป็น พ.ศ.
      return tmpNow;


    }

} DMT_task;


//----------------------------------------------------------------------------------------------------------------------------


/**class PbTask : public Task {
  protected:
    void setup() {

      pcf8574_3.begin();
      pcf8574_2.begin();
      pcf8574_1.begin();
      timeElapsed = millis();

      pcf8574_1.pinMode(P1, OUTPUT);
      pcf8574_1.digitalWrite(P1, 1);

      pcf8574_3.pinMode(P0, INPUT);

      pcf8574_3.pinMode(P2, INPUT);
      pcf8574_3.pinMode(P3, INPUT);
      pcf8574_3.pinMode(P4, INPUT);
      pcf8574_3.pinMode(P5, INPUT);
      pcf8574_3.pinMode(P6, INPUT);
      pcf8574_3.pinMode(P7, INPUT);


      pcf8574_2.pinMode(P0, OUTPUT);
      pcf8574_2.pinMode(P1, INPUT);
      pcf8574_2.pinMode(P2, OUTPUT);
      pcf8574_2.pinMode(P3, OUTPUT);
      pcf8574_2.pinMode(P4, OUTPUT);
      pcf8574_2.pinMode(P5, OUTPUT);
      pcf8574_2.pinMode(P6, OUTPUT);
      pcf8574_2.pinMode(P7, OUTPUT);
      pcf8574_2.digitalWrite(P0, 1);
      pcf8574_1.digitalWrite(P1, 1);
      pcf8574_2.digitalWrite(P2, 1);
      pcf8574_2.digitalWrite(P3, 1);
      pcf8574_2.digitalWrite(P4, 1);
      pcf8574_2.digitalWrite(P5, 1);
      pcf8574_2.digitalWrite(P6, 1);
      pcf8574_2.digitalWrite(P7, 1);


    }

    void loop() {
      uint8_t value0 = pcf8574_3.digitalRead(P0);
      uint8_t value1 = pcf8574_2.digitalRead(P1);
      uint8_t value2 = pcf8574_3.digitalRead(P2);
      uint8_t value3 = pcf8574_3.digitalRead(P3);
      uint8_t value4 = pcf8574_3.digitalRead(P4);
      uint8_t value5 = pcf8574_3.digitalRead(P5);
      uint8_t value6 = pcf8574_3.digitalRead(P6);
      uint8_t value7 = pcf8574_3.digitalRead(P7);

      if (value0 == 1) {
        pcf8574_2.digitalWrite(P0, 0);
      }
      else {
        pcf8574_2.digitalWrite(P0, 1);
      }


      if (value1 == 1) {
        pcf8574_1.digitalWrite(P1, 0);
      }
      else {
        pcf8574_1.digitalWrite(P1, 1);
      }



      if (value2 == 1) {
        pcf8574_2.digitalWrite(P2, 0);
      }
      else {
        pcf8574_2.digitalWrite(P2, 1);
      }


      if (value3 == 1) {
        pcf8574_2.digitalWrite(P3, 0);
      }
      else {
        pcf8574_2.digitalWrite(P3, 1);
      }


      if (value4 == 1) {
        pcf8574_2.digitalWrite(P4, 0);
      }
      else {
        pcf8574_2.digitalWrite(P4, 1);
      }


      if (value5 == 1) {
        pcf8574_2.digitalWrite(P5, 0);
      }
      else {
        pcf8574_2.digitalWrite(P5, 1);
      }

      if (value6 == 1) {
        pcf8574_2.digitalWrite(P6, 0);
      }
      else {
        pcf8574_2.digitalWrite(P6, 1);

      }



      if (value7 == 1) {
        pcf8574_2.digitalWrite(P7, 0);
      }
      else {
        pcf8574_2.digitalWrite(P7, 1);
      }

      delay(100);
    }



  } Pb_task;


**/






class Esprestart : public Task {
  protected:
    void setup() {

      pinMode(D9, OUTPUT);
      digitalWrite(D9, HIGH);//ให้ D9 เป็น 0 

    }
    void loop()  {
      delay(10000);
      digitalWrite(D9, LOW);//ให้ D9 เป็น 1 
      //delay(2000);
     // digitalWrite(D9, HIGH);//ให้ PinRx เป็น 0 ไม่มีไฟจ่ายจะลง Ground แทน

    }
} esprestart;

























//*****************************************************************************************************
//*******************************       void setup        *********************************************
//*****************************************************************************************************

void setup() {

  //****************************************************************************************************


  pinMode(D0, OUTPUT);//กำหนดโหมดใช้งานให้กับขา D0 เป็นขา สัญญาณไฟ ในสภาวะต่างๆ
  pinMode(D3, INPUT_PULLUP);//กำหนดโหมดใช้งานให้กับขา D3 เป็นขา กดปุ่ม ค้าง เพื่อตั้งค่า AP config
  pinMode(D4, OUTPUT);
  pinMode(D5, OUTPUT);
  pinMode(D6, OUTPUT);
  pinMode(D7, OUTPUT);

  pinMode(D9, OUTPUT);
  digitalWrite(D9, HIGH);//ให้ D9 เป็น 1 คือมีแรงดัน 5vdc จ่ายเข้าไปก่อน โดยการต่อ R330Ohm เข้า Ground จะได้มี Load ไม่ short cirrcuit



  // ให้ LED ทั้งหมดดับก่อน
  digitalWrite(D0, LOW);//ให้หลอด LED สีฟ้าดับก่อน
  digitalWrite(D4, LOW);
  digitalWrite(D5, LOW);
  digitalWrite(D6, LOW);
  digitalWrite(D7, LOW);



  lcd.begin(20, 4);


  lcd.createChar(1, WifiL1);
  lcd.createChar(2, WifiL2);
  lcd.createChar(3, WifiL3);
  lcd.createChar(4, Wifibase);
  lcd.createChar(5, intrnetok);
  lcd.createChar(6, blynk);



  //***************************************************************************************************

  Serial.begin(115200);


  //*************************    การ อ่าน  เขียนค่า WiFi + Password ]ลงใน Node MCU ESP8266   ************

  //read configuration from FS json
  Serial.println("mounting FS...");//แสดงข้อความใน Serial Monitor

  if (SPIFFS.begin()) {
    Serial.println("mounted file system");//แสดงข้อความใน Serial Monitor

    if (SPIFFS.exists("/config.json")) {
      //file exists, reading and loading
      Serial.println("reading config file");//แสดงข้อความใน Serial Monitor
      File configFile = SPIFFS.open("/config.json", "r");

      if (configFile) {
        Serial.println("opened config file");
        size_t size = configFile.size();
        // Allocate a buffer to store contents of the file.
        std::unique_ptr<char[]> buf(new char[size]);

        configFile.readBytes(buf.get(), size);
        DynamicJsonBuffer jsonBuffer;
        JsonObject& json = jsonBuffer.parseObject(buf.get());
        json.printTo(Serial);
        if (json.success()) {
          Serial.println("\nparsed json");//แสดงข้อความใน Serial Monitor
          strcpy(blynk_token, json["blynk_token"]);

        } else {
          Serial.println("failed to load json config");//แสดงข้อความใน Serial Monitor
        }
      }
    }
  } else {
    Serial.println("failed to mount FS");//แสดงข้อความใน Serial Monitor
  }
  //end read

  //*************************   จบการ อ่าน  เขียนค่า WiFi + Password ]ลงใน Node MCU ESP8266   ***************









  //**************************        AP AUTO CONNECT   **************************************************

  WiFiManagerParameter custom_blynk_token("blynk", "blynk token", blynk_token, 34);

  //WiFiManager
  //Local intialization. Once its business is done, there is no need to keep it around
  WiFiManager wifiManager;

  //set config save notify callback
  wifiManager.setSaveConfigCallback(saveConfigCallback);
  wifiManager.addParameter(&custom_blynk_token);
  lcd.clear();
  lcd.setCursor(0, 0);//กำหนดตำแหน่งที่0 ของแถวที่ 0 (อยู่ข้างบนสุดของจอ LCD)
  lcd.print("Wait 5 Sec AP Config"); //แถวที่ 0  ตำแหน่งที่  0  ให้แสดงตัวอักษร

  for (int i = 5; i > -1; i--) {
    digitalWrite(D0, HIGH);
    delay(500);
    digitalWrite(D0, LOW);
    delay(500);
    Serial.print (String(i) + " ");//แสดงข้อความใน Serial Monitor
    lcd.setCursor(10, 1);
    lcd.print(String(i) + " ");
    lcd.setCursor(0, 2);
    lcd.print("Button Press->config");

  }


  if (digitalRead(D3) == LOW) {
    digitalWrite(D0, HIGH);
    Serial.println("Button Pressed");//แสดงข้อความใน Serial Monitor
    lcd.clear();
    lcd.setCursor(4, 0);
    lcd.print("Button Pressed");
    lcd.setCursor(0, 1);
    lcd.print("Smartphone AP Config ");
    wifiManager.resetSettings();//ให้ล้างค่า SSID และ Password ที่เคยบันทึกไว้


    // wifiManager.autoConnect(); ใช้สร้างชื่อแอคเซสพอยต์อันโนมัติจาก ESP + ChipID

    if (!wifiManager.autoConnect("PUYIOT AP CONFIG")) {
      Serial.println("failed to connect and hit timeout");//แสดงข้อความใน Serial Monitor
      delay(3000);
      //reset and try again, or maybe put it to deep sleep
      ESP.reset();
      delay(5000);

    }
  }



  Serial.println("Connected.......OK!)");//แสดงข้อความใน Serial Monitor
  strcpy(blynk_token, custom_blynk_token.getValue());
  lcd.clear();
  lcd.setCursor(2, 2);
  lcd.print("Connected....OK!");
  delay(1000);


  //save the custom parameters to FS
  if (shouldSaveConfig) {
    Serial.println("saving config");//แสดงข้อความใน Serial Monitor
    lcd.setCursor(4, 1);
    lcd.print("saving config");
    delay(1000);
    DynamicJsonBuffer jsonBuffer;
    JsonObject& json = jsonBuffer.createObject();
    json["blynk_token"] = blynk_token;
    File configFile = SPIFFS.open("/config.json", "w");

    if (!configFile) {
      Serial.println("failed to open config file for writing");//แสดงข้อความใน Serial Monitor
      lcd.setCursor(4, 1);
      lcd.print("Failed> open config");
      delay(1000);
    }
    json.printTo(Serial);
    json.printTo(configFile);
    configFile.close();
    //end save
  }

  //**************************    จบ    AP AUTO CONNECT   **************************************************




  Serial.println("local ip"); //แสดงข้อความใน Serial Monitor
  delay(100);
  Serial.println(WiFi.localIP());//แสดงข้อความใน Serial Monitor

  lcd.clear();
  lcd.setCursor(2, 1);//กำหนดตำแหน่งที่0 ของแถวที่ 0 (อยู่ข้างบนสุดของจอ LCD)
  lcd.print("IP :"); //แถวที่ 0  ตำแหน่งที่  0  ให้แสดงตัวอักษร
  lcd.setCursor(6, 1);
  lcd.print(WiFi.localIP()); //แถวที่ 0  ตำแหน่งที่  0  ให้แสดงตัวอักษร




  // Blynk.config(blynk_token);////เริ่มการเชื่อมต่อ Blynk Server แบบปกติ
  Blynk.config(blynk_token, server, port);
  ////เริ่มการเชื่อมต่อ Blynk Server*********สำหรับ Server local ที่แจกให้ เพิ่ม, server, port  แค่นี้จบ



  timer.setInterval(30000L, reconnecting);  //Function reconnect
  //ตั้งเวลาส่งข้อมูลให้ Blynk Server ทุกๆ 30 วินาที
  //มาจากฟังชั่นเปิดใช้งาน BlynkTimer ซึ่งทำหน้าที่คล้าย ๆ interrupt timer หมายถึงเมื่อครบเวลาตามที่กำหนดไว้โปรแกรมหลักจะกระโดดไปทำงานในโปรแกรมตอบสนองที่กำหนดไว้
  // (1) ชื่อออฟเจคไว้อ้างอิง (ผู้ใช้งานตั้งชื่อเองในที่นี้ตั้งคำว่า "timer")
  // (2) กำหนดค่าช่วงเวลาที่ให้บอร์ดกระโดดไปทำงานในโปรแกรมตอบสนอง ในที่นี้กำหนดเป็น 30000L หมายถึงให้บอร์ดมาทำงานในโปรแกรมตอบสนองทุก ๆ 30 วินาที
  // (3) ชื่อโปรแกรมตอบสนอง (ฟังก์ชั่นย่อย)  ในที่นี้ตั้งชื่อว่า reconnecting  ซึ่งบอร์ดจะวนมาทำงานฟังก์ชั่นชื่อนี้ทุก ๆ เวลาที่กำหนด (ทุกๆ 30 วินาที)







  char_menu1(); //สร้าง Function
  Scheduler.start(&blynk_task);
  Scheduler.start(&rssi_print_task);
  Scheduler.start(&internet_print_task);
  Scheduler.start(&DMT_task);
  Scheduler.start(&esprestart);
  //Scheduler.start(&Pb_task);
  Scheduler.begin();

}


//*****************************************************************************************************
//*******************************     จบ  void setup        *********************************************
//*****************************************************************************************************


void char_menu1() {

  lcd.setCursor(0, 3);
  lcd.write(4);

  lcd.setCursor(13, 3);
  lcd.print("Blynk");

  lcd.setCursor(2, 3);
  lcd.print("Internet");

  lcd.setCursor(2, 2);
  lcd.print("PUYIOT");

}





//*****************************************************************************************************
//*******************************     void loop       *************************************************


void loop() {//Loop นี้จะใใช้งานไม่ได้ถ้าทำเป็น MultiTask แล้ว
}

//*******************************   จบ  void loop     *************************************************
//*****************************************************************************************************









//--------------------------------------------------------------------------------------------------------
void reconnecting()
{
  if (!Blynk.connected())
  {
    blynkIsDownCount++;
    BLYNK_LOG("blynk server is down! %d  times", blynkIsDownCount);
    Blynk.connect(5000);
  }
}
//--------------------------------------------------------------------------------------------------------


BLYNK_CONNECTED()
{

  Blynk.syncAll();//ให้ซิงค์ข้อมูลทั้งหมดล่าสุดจาก Blynk Server
  //Serial.println(".");//per debug  //แสดงข้อความใน Serial Monitor
}

อย่างนี้ก็ได้หรอ บางทีผมก็แอบกังวนอยู่ในๆ ว่าหากรันยาวๆ มันอาจจะ error ได้ การรีเซตในช่วงเวลา ที่ไม่ได้ ทำงานใน process ใดๆ เลย ก็เป็นอีกทางเลือกที่หน้าสนใจ ขนาดมือถือ แรงๆ สเถียรสูงหลายยี่ห้อ ใช้ไปนานๆ ยังต้องรีเซตใหม่เลย นับประสาอะไรกับ esp เล้า ขอบคุณมากครับพี่ ชี่ทางสว่างเลยครับ

ได้ครับ เรื่องเล็กๆ น้อย ๆ ที่เป็นพื้นฐานแบบนี้ เราต้องเอาให้ได้ก่อน แล้วพัฒนาต่อยอดไปเรื่อยๆ

ลืมไปครับ Code ตั้งเวลา


const long oneSecond = 1000;  // a second is a thousand milliseconds
const long oneMinute = oneSecond * 60;
const long oneHour   = oneMinute * 60;
const long fourHour   = oneHour * 4;
const long oneDay    = oneHour * 24;

 

void setup() {

      pinMode(D9, OUTPUT);
      digitalWrite(D9, HIGH);//ให้ D9 เป็น 0

    }
    void loop()  {
      delay(fourHour);
      digitalWrite(D9, LOW);//ให้ D9 เป็น 1
      //delay(2000);
      // digitalWrite(D9, HIGH);//ให้ PinRx เป็น 0 ไม่มีไฟจ่ายจะลง Ground แทน

    }

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

Diagram ตัวนี้ ผมปรับเปลี่ยนใหม่ กำลังทดสอบการใช้งานอยู่ ในรูปจะมี LED Switch บ้าง ผมแค่ทดสอบนะครับ แต่ผลลัพธ์ ตาม Diagram ครับ


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

แล้วตอนนี้ทำอะไรเสร็จแล้วบ้าง ติดปัญหาอะไรอยู่ตอนนี้

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

ตัวอย่างนะครับ ที่ผมใช้อยู่

ไฟฟ้า.xlsx (284.5 KB)

สร้างการคำนวณด้วย Excel ก่อน (ชื่อ Sheet “การคำนวณ”)เพื่อทดสอบว่าตรงหรือไม่ จากนั้นก็เอาไปเขียน code ครับ

 voltage = pzem.voltage();
    current = pzem.current();
    power = pzem.power();
    energy = pzem.energy();
    frequency = pzem.frequency();
    pf = pzem.pf();


    //1.2 อัตราปกติปริมาณการใช้พลังงานไฟฟ้าเกินกว่า 150 หน่วยต่อเดือน
    //ที่บ้านเราใช้ค่านี้ ประเภท 1125 คือ ใช้ไฟฟ้าเกิน 150 หน่วย/เดือน อัตราค่าบริการ 38.22 บาท/เดือน

    //1 -  150 หน่วยละ 3.2484  บาท

    if (energy >= 1 && energy <= 150) {
      kWh_1 = energy * 3.2484;
    }
    if (energy > 150) {
      kWh_1 = 150 * 3.2484;
    }

    //หน่วยที่  151    -  400 หน่วยละ 4.2218  บาท

    if (energy >= 151 && energy <= 400) {
      kWh_2 = (energy - 150) * 4.2218;
    }
    if (energy > 400) {
      kWh_2 = 250 * 4.2218;
      //401        -- >   หน่วยละ 4.4217  บาท
      kWh_3 = (energy - 400) * 4.4217;
    }

    //รวมค่าใช้จ่ายทั้งหมด
    kWh_T = kWh_1 + kWh_2 + kWh_3;
    kWh_T1 = kWh_T + 38.22 + (energy * Ft_float);

    Electric_bill = kWh_T1 + (kWh_T1 * 0.07);

ส่วนการ เซ็ดค่าft ประจำเดือน ผมใช้ วิธีการตั้งค่าผ่าน Text input ของ Blynk ครับ โดยเข้าไปเชคค่า ft ที่นี่่ก่อน
https://www.erc.or.th/ERCWeb2/Front/StaticPage/StaticPage.aspx?p=186&Tag=ค่าไฟฟ้าโดยอัตโนมัติ%20(Ft)&muid=23&prid=114";

จากนั้นป้อนเข้าไปใน Text input ของ Blynk แล้วให้เก็บไว้ใน Eeprom ของ ESP แล้ว get ค่า ออกมาคำนวณต่อครับ

BLYNK_WRITE(V28)//ค่า  Ft  ที่ตั้งจาก Blynk เข้าเครื่อง  สร้าง Text input ที่ Blynk App
{
  Ft_st = param.asString();//รับค่าข้อความจาก Blynk เข้ามา เก็บในรูปแบบ String
  Ft_float = Ft_st.toFloat();//แปลงค่าจาก String เป็น float
  EEPROM.put(200, Ft_float); //เขียนค่า Ft_float  ที่เป็น float  ลงใน Address xxx
  EEPROM.commit(); //จบการเขียน
  Ft_float = EEPROM.get(200, Ft_float);//อ่าน ค่า Ft_float ที่เป็น float จาก Address xxx มาใช้งาน
}

ย้อนกลับไปดู code ข้างบน บรรทัด kWh_T1 = kWh_T + 38.22 + (energy * Ft_float);

พี่เคยใช้ netpie ไหมครับ ทำแบบที่พี่ทำใน blynk เซ็ดค่า ft อะครับ ผมงมตรงนี้อยู่และครับพี่

ที่ผมแนะนำไป มีหลักการคือ หาระบบ การเชื่อมต่อ ที่สามารถป้อนข้อมูล เข้ามาใน ESP ของเราให้ได้เท่านั้นเองครับ แต่รูปแบบการนำข้อมูลเข้า ก็แล้วแต่ใครจะรู้ว่าระบบอะไรสามารถนำข้อมูลเข้า ESP ได้
netpie ผมไม่เคยใช้ครับ ใช้แต่ Blynk

ตัวอย่างครับ

ขอคำแนะนำหน่อยได้ไหมครับ
ผมทำโปรเจค ให้ esp32 ดึงว่าค่าเวลามาจาก server แล้วตั้งเวลาว่า 10 โมงเช้า จ่าย 1 ออกมา
4 โมงเย็นจ่าย 0 ออกมา แต่ในช่วงนี้บอร์ดจะมีคำสั่งให้ reset บอร์ด ซึ่งเมื่อ reset แล้ว ค่า 1 ที่จ่ายออกมาจะกลายเป็น 0 ก่อนถึงเวลาที่กำหนด ตือ 4 โมงเย็น ควรใช้คำสั่งแบบไหนดีครับ ผมลองแล้วมันยังไม่เวิร์คครับ

ขอบคุณครับ

ควรมีการเก็บคำสั่งปัจจุบันไว้ใน EEPROM ครับ หากมีการรีเซตเมื่อเริ่มทำงานใหม่เราก็ให้ไปอ่านค่าเดิมก่อนดับจาก EEPROM ก่อน

ขอบคุณครับ