ว่าด้วยเรื่อง Pzem 004t v3.0 จะวัดพลังงาน+ค่าใช้จ่าย/เดือน

สำหรับ Post นี้ เป็นของจริงแล้วครับ​ แต่ต้องผ่านการทดสอบก่อนโดยผมจะนำมาแชร์ Project กัน เริ่มเลยนะครับ
Diagram การต่อสาย

ความต้องการของ Project (เพื่อป้องกันความผิดพลาดเรื่องของ Version และตรวจสอบย้อนหลังได้)

  1. Arduino IDE Version 1.8.7
  2. WiFiManager Version 0.14.0
  3. Blynk Version 0.5.4
  4. ArduinoJson Version 5.13.3
  5. uRTCLib By Naguissa Version 6.2.4
  6. New-LiquidCrystal-master Version 6.2.4 :crazy_face:
  7. PZEM-004T-v30-master
    เอาเป็นว่า ข้อ 2 - 7 มีให้ Download ครับ
  8. ESP8266Scheduler https://drive.google.com/file/d/1Rx-S8AXVycXHkHUely-kQKZ0nvagssS3/view?usp=sharing

ต่อไปมากล่าวถึงคุณลักษณะของ Proj นี้กันบ้าง ว่าทำอะไรได้บ้าง
0. Code ที่เขียนไว้คิดค่าไฟ และค่า Ft เป็นของการไฟฟ้าส่วนภูมิภาค
*** 1.2 อัตราปกติปริมาณการใช้พลังงานไฟฟ้าเกินกว่า 150 หน่วยต่อเดือน*** ส่วนของท่านใดที่ไม่ใช่แบบผมก็ประยุกต์จาก Project ผมได้ครับ

  1. ดูค่า พารามิเตอร์ ของ PZEM-004T-v30 ตามที่มันระบุไว้ได้ เช่น แรงดันไฟฟ้า กระแสไฟฟ้า ความถี่ไฟฟ้า วัตต์ กิโลวัตต์/ชั่วโมง (โดยค่านี้จะเก็บไว้ที่ตัว PZEM-004T-v30 เลย ไม่ต้องกลัวว่าไฟดับแล้ว ค่า กิโลวัตต์/ชั่วโมง จะหาย ถ้าต้องการ ให้ค่ามันเป็น 0 ก็ เขียน Code reset เอา ) ค่า Power Factor
  2. ดูค่าไฟเป็น เงิน บาท/เดือน ได้เลย แบบ Real time โดย + ค่าบริการและภาษี 7% แล้ว
  3. สามารถตั้งค่า ft /เดือน เอง ได้ โดย กดปุ่มที่ Ft/M ที่ Blynk เพื่อ Link เข้า Web ที่แสดงค่า Ft ในช่วงต่างของปี โดยการไฟฟ้า จะออกมาเป็นช่วง ๆ เช่น มกราคม – เมษายน 2563 ** Ft ขายปลีก = -11.60 สตางค์ ก็ = -0.116 บาท

Link : http://www.erc.or.th/ERCWeb2/Front/StaticPage/StaticPage.aspx?p=186&Tag=ค่าไฟฟ้าโดยอัตโนมัติ%2

Link นี้ผมทำไว้เพื่อสะดวกเวลาเปิดหน้า Web ด้วย Blynk ก็จะเห็นค่าตัวเลข ให้เราเอามาป้อนเพื่อกำหนดค่า Ft ได้ เลย เพราะโดยปกติการไฟฟ้า จะออกมาเป็นไฟล์ .PDF ทำให้ไม่สะดวกเป็นอย่างมาก

  1. ตรวจสอบค่าไฟฟ้าย้อนหลังได้ จากการไฟฟ้าส่วนภูมิภาค โดยกดปุ่ม Bill/M เพื่อ Link เข้า Web ที่แสดงเป็นการแสดงค่าใช้จ่าย ย้อนหลัง ประมาณ 6-7 เดือน โดยเราต้องป้อน หมายเลขผู้ใช้ไฟ้า และรหัสเครื่องวัด เข้าไป ระบบจึงจะแสดงกราฟออกมา

Link : https://www.pea.co.th/e-service/สอบถามประวัติการใช้ไฟ
5. ดูอัตราการคิดค่าไฟฟ้าได้ โดยกดปุ่ม Rate/M เพื่อ Link เข้า Web ที่แสดง อัตราค่าไฟฟ้า ประเภทที่ 1 บ้านอยู่อาศัย เพื่อสะดวกในการดูข้อมูล

Link : https://webcache.googleusercontent.com/search?q=cache:hrvodg5Q4EUJ:https://www.pea.co.th/Portals/0/Document/Rate2015Update.pdf+&cd=3&hl=th&ct=clnk&gl=th
*** หมายเหตุ เป็น web cache***

  1. สามารถกำหนดค่า Ft จาก Blynk เข้าไปเก็บใน EEPROM ของ ESP8266 ได้ ดังนั้นจึงไม่ต้องกังวลว่า กรณี ESP8266 ไม่สามารถ เชื่อม WiFi Internet +Blynk Server ได้แล้ว เรายังสามารถดูค่าจริง จาก จอ LCD ได้ โดยมีข้อแม้ว่า ทุกครั้งที่มีการเปลี่ยนค่า Ft จะต้องมีการป้อนค่าจาก Blynk เสมอ

  2. สามารถกำหนดค่า วันที่ ชั่วโมง นาที ในการตัดบิลค่าไฟฟ้า ประจำเดือน จาก Blynk เข้าไปเก็บใน EEPROM ของ ESP8266 ได้ ดังนั้นจึงไม่ต้องกังวลว่า กรณี ESP8266 ไม่สามารถ เชื่อม WiFi Internet +Blynk Server ได้แล้ว เรายังสามารถดูค่าจริง จาก จอ LCD ได้ โดยมีข้อแม้ว่า ทุกครั้งที่มีการเปลี่ยนค่า วันที่ ชั่วโมง นาที จะต้องมีการป้อนค่าจาก Blynk เสมอ และเมื่อถึงวันเวลาดังกล่าว ที่เรากำหนดไว้ ระบบจะทำการส่ง Email แจ้งค่าไฟมาให้เราในแต่ละเดือน พร้อมทั้ง Reset ค่า kWh ให้เราอัตโนมัติ

  3. สามารถ Reset ค่า kWh โดย การกดปุ่มที่เครื่อง ค้างไว้ 5 วินาที หรือ กดปุ่ม Reset ค่า kWh จาก Blynk ก็ได้ หรือ Reset แบบ Auto ตามข้อที่ 7

  4. มีกราฟแสดง ค่าที่เราสนใจ เช่น Watt kWh ค่าไฟฟ้า แรงดัน กระแส อันนี้ท่านที่เคยใช้งาน blynk ทำได้อยู่แล้ว

  5. ดูค่า พารามิเตอร์ แบบ real time ทั้ง Online (ดูจาก Blynk) หรือ Offline (จอ LCD )ก็ได้

PZEM Project Qr CODE clone

พักก่อนครับ…19.02 03-03-2563

ต่อครับ 09.41 03-03-2563

Code Final ครับ (ใน Code ผมอธิบายการทำงานบางส่วนเอาไว้แล้ว)


#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>
#include <FS.h>
#include <DNSServer.h>
#include <ArduinoJson.h>
#define BLYNK_MAX_SENDBYTES 1200
#include <BlynkSimpleEsp8266.h>
#include <EEPROM.h>


//------------------------------        การกำหนดค่าในส่วนของ Blynk         ------------------------------------------------//
#define BLYNK_DEBUG
#define BLYNK_PRINT Serial

int blynkIsDownCount = 0;

char blynk_token[34] = "8dwBaSBOE8htLFrK37JPAYB1hm8TaQkU";//ใส่ Blynk_token ของเราที่ Blynk ส่งมาทาง Email ตอน Create Project ใหม่

BlynkTimer timer;

//----------------------------------  กำหนดหมายเลขของขาของ Node MCU ESP 8266  --------------------------------------------//

#define D0 16 // ใช้ไฟ LED สีฟ้า ของบอร์ด MCU ESP8266 ให้มีสัญญาณไฟกระพริบ ตาม Code ที่เขียน

#define D3 0 // ใช้เป็นปุ่มกด เพื่อเข้า AP Config ได้ตามความต้องการของผู้ใช้
//------------------------------------------------------------------------------------------------------------------------//

#include <Scheduler.h>



// ------------------------โหลดไลบารี่ของจอ LCD มาใช้งาน โดยแบบนี้จะสามารถ Create Characterได้ ---------------------------------//
#include <LCD.h>                          // บรรทัดที่ 1 และ 2 สามารถสลับบรรทัดกันได้
#include <Wire.h>                         // บรรทัดที่ 1 และ 2 สามารถสลับบรรทัดกันได้
#include <LiquidCrystal_I2C.h>            //บรรทัดนี้ต้องอยู่ในบรรทัดที่ 3 เท่านั้น ถ้าไปอยู่บรรทัดที่ 1 และ 2 จะคอมไพล์ไม่ผ่าน
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); //// ตั้งค่า Address ของอุปกรณ์จอ LCD ที่มีการเชื่อมต่อแบบ I2C
//------------------------------------------------------------------------------------------------------------------------//



bool shouldSaveConfig = false;

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


//-------------สำหรับ Server local ที่แจกให้ เพิ่ม **** แค่ 2 บรรทัดนี้--------------   (ถ้าเป็น Blynk Server ปกติไม่ต้องใส่)  ----------//
char server[] = "oasiskit.com";
int port = 8080;
//------------------------------------------------------------------------------------------------------------------------//


#include <PZEM004Tv30.h>
PZEM004Tv30 pzem(12, 13); // 12(D6)=RX , 13(D7) = TX  :  TX->D6(GPIO012),RX->D7(GPIO013)
//ตัวแปรรับค่า Ft จาก Blynk มาเก็บใน EEPROM
float Ft;
String Ft_1;
float Ft_2;

//ตัวแปรรับค่า วันที่ จาก Blynk มาเก็บใน EEPROM
float Rst_D;
String Rst_D1;
float Rst_D2;

//ตัวแปรรับค่า ชั่วโมง จาก Blynk มาเก็บใน EEPROM
float Rst_H;
String Rst_H1;
float Rst_H2;

//ตัวแปรรับค่า นาที จาก Blynk มาเก็บใน EEPROM
float Rst_M;
String Rst_M1;
float Rst_M2;

//ตัวแปรรับค่า ค่าไฟประเดือน 
float Electric_bill;
float kWh_1;
float kWh_2;
float kWh_3;
float kWh_T;
float kWh_T1;

//กดปุ่ม Reset kWh จาก Blynk
int Blynkreset_kWh;
WidgetLED led_rst_kWh(V12);//จะ ON เมื่อกดปุ่มค้างไว้ 5 วินาที


//RTC Library
#include "Arduino.h"
#include "Wire.h"
#include "uRTCLib.h"
// uRTCLib rtc;
uRTCLib rtc(0x68);

//ชุดกำหนดการส่ง Email แค่ครั้งเดียว
int Email_status = 0;
int Email_status1 = 0;


BLYNK_WRITE(V10)

{
  Ft_1 = param.asString();//รับค่าข้อความจาก Blynk เข้ามา เก็บในรูปแบบ String

  Ft_2 = Ft_1.toFloat();//แปลงค่าจาก String เป็น Float
  //เราป้อนค่า จาก Blynk เป็น String = -0.116 ให้ Ft_1 รับค่ามา
  //Ft จะรับค่าการแปลง จาก Ft_1 เป็น Float = -0.12
  //จะเห็นว่า ค่า Folat จะปัดค่าเป็นจุดทศนิยม ไปเป็น 2 ตำแหน่งจะไม่มากกว่านี้เนื่องด้วยความสามารถตัวของอุปกรณ์เอง
  //ทำให้ค่าเพี้ยนไป ประมาณ 3.44%  ทำให้ค่าไฟ/เดือน น้อยกว่าค่าจริงไป 3.44% ประมาณ 0.64(150หน่วย) - 2.14(500หน่วย) บาท
  //โปรเจคนี้จะไม่เปลี่ยนค่า ใดๆ เพราะค่าต่างกันเล็กน้อย (1 เดือน ใช้ไฟไม่ถึง 500 หน่วยแน่นอน)

  //ชุดนี้ทำขึ้นในกรณีที่ ไม่ได้เชื่อมต่อกับ App Blynk ก็ยังสามารถดูค่าทั้งหมดได่อย่างถูกต้อง แต่ทุกครั้งที่มีการเปลี่ยนค่า Ft วันที่ ชั่วโมง นาที  จะต้องถูกกำนดค่าผ่าน App Blynk มาทุกครั้ง
  
  EEPROM.put(0, Ft_2); //เขียนค่า Ft_2 ที่เป็น Float ลงใน Address 0
  EEPROM.commit(); //จบการเขียน

  Ft = EEPROM.get(0, Ft_2);//อ่าน ค่า Ft_2 ที่เป็น Float จาก Address 0
  Serial.println(Ft);//แสดงค่า Ft ใน Serial Monitor
  lcd.clear();
  lcd.setCursor(0, 1);
  lcd.print("...... Sync Ft .....");
  lcd.setCursor(6, 3);
  lcd.print(Ft, 3);
  delay(2000);
  lcd.clear();

}


BLYNK_WRITE(V20)//Reset kWh Automatic  ตามวันที่  ที่ตั้งจาก Blynk เข้าเครื่อง

{
  Rst_D1 = param.asString();//รับค่าข้อความจาก Blynk เข้ามา เก็บในรูปแบบ String

  Rst_D2 = Rst_D1.toFloat();//แปลงค่าจาก String เป็น Float

  //ชุดนี้ทำขึ้นในกรณีที่ ไม่ได้เชื่อมต่อกับ App Blynk ก็ยังสามารถ Rst ค่า kWh ได้ แต่ทุกครั้งที่มีการเปลี่ยนค่า วัน เวลา  จะต้องถูกกำนดค่าผ่าน App Blynk มาทุกครั้ง
  EEPROM.put(20, Rst_D2); //เขียนค่า Rst_D2 ที่เป็น Float ลงใน Address 20
  EEPROM.commit(); //จบการเขียน

  Rst_D = EEPROM.get(20, Rst_D2);//อ่าน ค่า Rst_2 ที่เป็น Float จาก Address 20
  Serial.println(Rst_D);//แสดงค่า Rst ใน Serial Monitor
  lcd.clear();
  lcd.setCursor(0, 1);
  lcd.print("Sync Auto Rst By Day");
  lcd.setCursor(0, 2);
  lcd.print("     Day:  ");
  lcd.setCursor(10, 2);
  lcd.print(Rst_D, 0);
  delay(2000);
  lcd.clear();
}





BLYNK_WRITE(V21)//Reset kWh Automatic  ตามชั่วโมง  ที่ตั้งจาก Blynk เข้าเครื่อง

{
  Rst_H1 = param.asString();//รับค่าข้อความจาก Blynk เข้ามา เก็บในรูปแบบ String

  Rst_H2 = Rst_H1.toFloat();//แปลงค่าจาก String เป็น Float

  //ชุดนี้ทำขึ้นในกรณีที่ ไม่ได้เชื่อมต่อกับ App Blynk ก็ยังสามารถ Rst ค่า kWh ได้ แต่ทุกครั้งที่มีการเปลี่ยนค่า วัน เวลา  จะต้องถูกกำนดค่าผ่าน App Blynk มาทุกครั้ง
  EEPROM.put(30, Rst_H2); //เขียนค่า Rst_H2 ที่เป็น Float ลงใน Address 30
  EEPROM.commit(); //จบการเขียน

  Rst_H = EEPROM.get(30, Rst_H2);//อ่าน ค่า Rst_H2 ที่เป็น Float จาก Address 30
  Serial.println(Rst_H);//แสดงค่า Rst ใน Serial Monitor
  lcd.clear();
  lcd.setCursor(0, 1);
  lcd.print("Sync AutoRst By Hour");
  lcd.setCursor(0, 2);
  lcd.print("    Hour:  ");
  lcd.setCursor(10, 2);
  lcd.print(Rst_H, 0);
  delay(2000);
  lcd.clear();

}



BLYNK_WRITE(V22)//Reset kWh Automatic  ตามนาที  ที่ตั้งจาก Blynk เข้าเครื่อง

{
  Rst_M1 = param.asString();//รับค่าข้อความจาก Blynk เข้ามา เก็บในรูปแบบ String

  Rst_M2 = Rst_M1.toFloat();//แปลงค่าจาก String เป็น Float

  //ชุดนี้ทำขึ้นในกรณีที่ ไม่ได้เชื่อมต่อกับ App Blynk ก็ยังสามารถ Rst ค่า kWh ได้ แต่ทุกครั้งที่มีการเปลี่ยนค่า วัน เวลา  จะต้องถูกกำนดค่าผ่าน App Blynk มาทุกครั้ง
  EEPROM.put(40, Rst_M2); //เขียนค่า Rst_H2 ที่เป็น Float ลงใน Address 0
  EEPROM.commit(); //จบการเขียน

  Rst_M = EEPROM.get(40, Rst_M2);//อ่าน ค่า Rst_M2 ที่เป็น Float จาก Address 40
  Serial.println(Rst_M);//แสดงค่า Rst ใน Serial Monitor
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("   Sync Auto Rst    ");
  lcd.setCursor(0, 1);
  lcd.print("     By Minute      ");
  lcd.setCursor(0, 3);
  lcd.print("  Minute:  ");
  lcd.setCursor(10, 3);
  lcd.print(Rst_M, 0);
  delay(2000);
  lcd.clear();

}











BLYNK_WRITE(V11)//Reset kWh ภายใน 5 วินาที จาก Blynk
{

  int pinValue = param.asInt();
  if (pinValue == 1) {
    Blynkreset_kWh = 1;
  }
  if (pinValue == 0) {
    Blynkreset_kWh = 0;
  }
}







//การเชื่อมต่อ Blynk Server
class Task_1 : public Task {
  protected:
    void setup() { }


    void loop()  {

      //-----------------------------------------------------------------------------------------------------------//
      if (Blynk.connected())
      {
        Blynk.run();
        digitalWrite(D0, LOW);

      } else {

        digitalWrite(D0, LOW);
        delay(200);
        digitalWrite(D0, HIGH);
        delay(100);

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

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

      delay(500);

    }
} Task_1_task;



//แสดงค่า ต่างๆ ของ PZEM ออกมา
class Task_2 : public Task {
  protected:
    void setup() { }


    void loop()  {

      float voltage = pzem.voltage();
      if (voltage != NAN) {
        //Serial.print("Voltage: "); Serial.print(voltage); Serial.println("V");
        lcd.setCursor(1, 0);
        lcd.print(voltage, 0);
        lcd.setCursor(4, 0);
        lcd.print("Vac");
        Blynk.virtualWrite(V1, voltage);
      } else {

      }


      float current = pzem.current();
      if (current != NAN) {
        //Serial.print("Current: "); Serial.print(current); Serial.println("A");
        lcd.setCursor(13, 0);
        lcd.print(current, 2);
        lcd.print(" A");
        Blynk.virtualWrite(V2, current);
      } else {

      }

      float power = pzem.power();
      if (current != NAN) {
        lcd.setCursor(0, 1);
        lcd.print(power, 2);
        lcd.setCursor(8, 1);
        lcd.print("W");


        Blynk.virtualWrite(V3, power);
      } else {

      }

      float energy = pzem.energy();
      if (current != NAN) {
        lcd.setCursor(10, 1);
        lcd.print(energy, 2);
        lcd.print(" kWh");
        Blynk.virtualWrite(V4, energy);
      } else {

      }

      float frequency = pzem.frequency();
      if (current != NAN) {
        lcd.setCursor(8, 0);
        lcd.print(frequency, 0);
        lcd.setCursor(10, 0);
        lcd.print("Hz");
        Blynk.virtualWrite(V5, frequency);
      } else {

      }

      float pf = pzem.pf();
      if (current != NAN) {

        Blynk.virtualWrite(V6, pf);
      } else {

      }
      delay(4000);

    }//loop



} Task_2_task;



//คิดค่าไฟฟ้า ตามการใช้งานที่บ้าน ของเรามากกว่า 150 หน่วย/เดือน ใครน้อยกว่านี้ก็คิดสูตรเอง

class Task_3 : public Task {
  protected:
    void setup() { }

    void loop()  {


      float energy = pzem.energy();

      // กดปุ่มที่หน้าเครื่อง 5 วินาที เพื่อ Reset kWh
      if (digitalRead(D3) == LOW) {
        delay(3000);
        pzem.resetEnergy();

      }

      // กดปุ่มจาก Blynk 5 วินาที เพื่อ Reset kWh กดค้างจนกว่า LED จะดับ
      if (Blynkreset_kWh == 1) {
        led_rst_kWh.on();
        delay(3000);
        pzem.resetEnergy();
        led_rst_kWh.off();
        pzem.resetEnergy();

      }
      if (Blynkreset_kWh == 0) {

        led_rst_kWh.off();

      }


      //  Reset kWh  แบบ Auto โดยการตั้งค่ามาจาก Blynk โดยเก็บไว้ใน EEPROM ของเครื่อง
      // ส่ง Email 1 ครั้งเท่านั้น
      if (Rst_D == rtc.day() && Rst_H == rtc.hour() &&  Rst_M == rtc.minute() && Email_status == 0) {
        pzem.resetEnergy();
        //Serial.println("reset kWh");มันจะ Reset ซ้ำ กันใน 1 นาทีนี้ และยกเลิกจนกว่าจะขึ้นนาทีใหม่
        String body = String("ค่าไฟฟ้าประจำเดือนที่ ") + (rtc.month() - 1) + String(" เป็นจำนวนเงิน ") + Electric_bill + String(" บาท ระบบทำการ Reset kWh = 0 แล้ว ***ให้ตรวจสอบค่า Ft ประจำเดือนด้วย***  By  PUYIOT");
        Blynk.email("xxxxxxxxxx@gmail.com", "แจ้งค่าไฟฟ้าประจำเดือน ", body);
        delay(500);
        Email_status = 1;
        Email_status1 = 0;
      }
      else if (Rst_D == rtc.day() && Rst_H == rtc.hour() &&  Rst_M == rtc.minute() && Email_status == 1) {
        delay(10);
        Email_status1 = 1;
      }

      if (Rst_M != rtc.minute() && Email_status1 == 1 ) {
        delay(10);
        Email_status = 0;
      }



      //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);

      Electric_bill = kWh_T1 + (kWh_T1 * 0.07);

      lcd.setCursor(0, 3);
      lcd.print("B/M: ");
      lcd.setCursor(5, 3);
      lcd.print(Electric_bill , 2);
      lcd.setCursor(12, 3);
      //lcd.print("Bath");
      Blynk.virtualWrite(V7, Electric_bill);


      lcd.setCursor(13, 3);
      lcd.print(Rst_D, 0);
      //lcd.print("D");
      lcd.setCursor(15, 3);
      lcd.print(Rst_H, 0);
      lcd.setCursor(17, 3);
      lcd.print(":");
      //lcd.print("H");
      lcd.setCursor(18, 3);
      lcd.print(Rst_M, 0);

      delay(2000);

    }//loop






} Task_3_task;



//แสดง dd:mm:yy   hh:mm
class Task_4 : public Task {
  protected:
    void setup() { }

    void loop()  {
      rtc.refresh();
      int year_ = rtc.year() + 43; //+43 เพื่อให้ได้ปี พ.ศ. 63

      lcd.setCursor(0, 2);
      
//เติม 0 กรณีเป็นเลข วัน เดือน ชม. นาที วินาที ตัวเดียว
      if (rtc.day() < 10)
      {
        lcd.print("0");
        lcd.print(rtc.day());
      }
      else lcd.print(rtc.day());
      lcd.print('-');


      if (rtc.month() < 10)
      {
        lcd.print("0");
        lcd.print(rtc.month());
      }
      else lcd.print(rtc.month());
      lcd.print('-');

      lcd.print(year_);

      lcd.setCursor(12, 2);

      if (rtc.hour() < 10)
      {
        lcd.print("0");
        lcd.print(rtc.hour());
      }
      else lcd.print(rtc.hour());

      lcd.print(':');



      if (rtc.minute() < 10)
      {
        lcd.print("0");
        lcd.print(rtc.minute());
      }
      else lcd.print(rtc.minute());

      lcd.print(':');



      if (rtc.second() < 10)
      {
        lcd.print("0");
        lcd.print(rtc.second());
      }
      else lcd.print(rtc.second());


      delay(1000);



    }
} Task_4_task;








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

void setup() {

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


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

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


  Serial.begin(115200);
  //-------------------------------//

  EEPROM.begin(512);
  
  //ต้องการให้รู้ว่า ค่า Ft ที่เป็น Float ที่เก็บใน EEPROM มีค่า = ค่าที่ถูกป้อนมาจาก Bylnk จริงๆหรือปล่าว
  Ft = EEPROM.get(0, Ft_2);
  Serial.print("Ft in Void setup : ");
  Serial.println(Ft);
  
//ต้องการให้รู้ว่า ค่า วันที่ ที่เป็น Float ที่เก็บใน EEPROM มีค่า = ค่าที่ถูกป้อนมาจาก Bylnk จริงๆหรือปล่าว
  Rst_D = EEPROM.get(20, Rst_D2);
  Serial.print("Day in Void setup : ");
  Serial.println(Rst_D);
  
//ต้องการให้รู้ว่า ค่า ชั่วโมง ที่เป็น Float ที่เก็บใน EEPROM มีค่า = ค่าที่ถูกป้อนมาจาก Bylnk จริงๆหรือปล่าว
  Rst_H = EEPROM.get(30, Rst_H2);
  Serial.print("Hour in Void setup : ");
  Serial.println(Rst_H);
  
//ต้องการให้รู้ว่า ค่า นาที ที่เป็น Float ที่เก็บใน EEPROM มีค่า = ค่าที่ถูกป้อนมาจาก Bylnk จริงๆหรือปล่าว
  Rst_M = EEPROM.get(40, Rst_M2);
  Serial.print("Minute in Void setup : ");
  Serial.println(Rst_M);
  

  lcd.begin(20, 4);
  lcd.clear();




#ifdef ARDUINO_ARCH_ESP8266
  Wire.begin(4, 5); // GPIO4 = D2 and GPIO5 = D1 on ESP8266
#else
  Wire.begin();
#endif

  //rtc.set(0, 46, 11, 3, 3, 3, 20);//ใช้เฉพาะตั้งเวลา ถ้าจะตั้งก็ เอา // ออก เมื่อตั้งได้ตรงแล้วก็เอา // ใส่กลับไปเหมือนเดิม
  //  RTCLib::set(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year)







  //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



  //**************************        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);


  for (int i = 5; i > -1; i--) {  // นับเวลาถอยหลัง 5 วินาทีก่อนกดปุ่ม AP Config
    digitalWrite(D0, HIGH);
    delay(500);
    digitalWrite(D0, LOW);
    delay(500);
    Serial.print (String(i) + " ");//แสดงข้อความใน Serial Monitor
  }


  if (digitalRead(D3) == LOW) {
    digitalWrite(D0, LOW);
    Serial.println("Button Pressed");//แสดงข้อความใน Serial Monitor

    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());


  //save the custom parameters to FS
  if (shouldSaveConfig) {
    Serial.println("saving config");//แสดงข้อความใน Serial Monitor
    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

    }
    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
  Serial.println("gateway");
  delay(100);
  Serial.println(WiFi.gatewayIP());
  Serial.println("subnetMask");
  delay(100);
  Serial.println(WiFi.subnetMask());
  Serial.println("SSID");
  delay(100);
  Serial.println(WiFi.SSID());
  Serial.println("Password");
  delay(100);
  Serial.println(WiFi.psk());


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



  timer.setInterval(30000L, reconnecting);  //Function reconnect




  Scheduler.start(&Task_1_task);
  Scheduler.start(&Task_2_task);
  Scheduler.start(&Task_3_task);
  Scheduler.start(&Task_4_task);

  Scheduler.begin();




}


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



//------------------------------------------------------------------------------------------------------------------------//
//*********************************************       void Loop        ***************************************************//
//------------------------------------------------------------------------------------------------------------------------//


void loop() {



}

//------------------------------------------------------------------------------------------------------------------------//
//*********************************************      จบ 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

}


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

1 Likes