ESP32 + Tasks on Multicore + WiFimanager + Blynk + Temp&Humid I2C + Line Notify

สำหรับในหัวข้อนี้ผมจะลองมาใช้งาน ESP32 NodeMCU Wi-Fi and Bluetooth กันบ้างดีกว่าหลังจากที่นำ WiFi Manager มาร่วมใช้งานได้แล้วต่อไปก็จะนำตัวเซ็นเซอร์ที่เป็นอุณหภูมิและความชื้นที่ใช้การสื่อสารแบบ i2c นำมาร่วมใช้งานด้วยกัน พร้อมกันนั้นจะมีการตั้งค่าการควบคุมใน Application blynk พร้อมส่งข้อความไปที่ Line notify โดยถ้าอุปกรณ์ทำงาน เข้าเงื่อนไขของ Temp หรือ Humid Line ส่งข้อความจะส่งแยกกัน แต่ถ้าเข้าเงื่อนไขทั้งคู่พร้อมกัน Line จะส่งข้อความมา 2 ครั้ง โดยแบ่งงานกันทำแบบ Multicore ชุด WiFi Managerและชุดหลัก จะทำงานบน Core1 ส่วน เซ็นเซอร์ที่เป็นอุณหภูมิและความชื้นจะทำงานบน Core0 ครับ

ความต้องการของ Project
ARDUINO IDE 1.8.7
Board Manager ESP32 Version 1.0.3
Library
- Arduino json Version 5.13.5
- Blynk Version 0.6.1
- WIFIMANAGER-ESP32-master
-https://github.com/zhouhan0126/WIFIMANAGER-ESP32
- arduino-SHTC3
- https://www.arduinoall.net/arduino-tutor/code/arduino-SHTC3.rar
- TridentTD_LineNotify

Diagram การต่อสาย

Code ok (UP Date 23_01_2563 : 23:50)

//อ้างจาก https://randomnerdtutorials.com/esp32-dual-core-arduino-ide/

#include <FS.h>                   //this needs to be first, or it all crashes and burns...
#include <SPIFFS.h>//เพิ่ม

#include <WiFi.h>          //https://github.com/esp8266/Arduino
#include <WiFiClient.h>


//needed for library
#include <DNSServer.h>
#include <WebServer.h>
#include <WiFiManager.h>          //https://github.com/tzapu/WiFiManager
#include <ArduinoJson.h>       //Ver 5.13.4   //https://github.com/bblanchon/ArduinoJson
//------------------------------------------------------------------------------------------------------------------------//
#include <BlynkSimpleEsp32.h>          //  Blynk_Release_v0.6.1 
//------------------------------------------------------------------------------------------------------------------------//

#include <TridentTD_LineNotify.h>
#define LINE_TOKEN  "QerWyEZdBShylI3iTTxKz1Pk8Zo1vLy2NQa7AXFgYLM"
//------------------------------        การกำหนดค่าในส่วนของ Blynk         ------------------------------------------------//
#define BLYNK_DEBUG
#define BLYNK_PRINT Serial
int blynkIsDownCount = 0;

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

BlynkTimer timer;  //เรียกใช้การตั้งเวลาของ Blynk

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

const int Ledblynk = 2;                     // ใช้ไฟ LED สีฟ้า ของบอร์ด MCU ESP32 ให้มีสัญญาณไฟกระพริบ ตาม Code ที่เขียน
const int AP_Config = 23;                // ใช้เป็นปุ่มกด เพื่อเข้า AP Config ได้ตามความต้องการของผู้ใช้
//------------------------------------------------------------------------------------------------------------------------//



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


TaskHandle_t Task1;



const int led1 = 2;
const int led2 = 4;



float temp;     //รับค่าการอ่าน Temp
float humid;    //รับค่าการอ่าน Humid







//Temp Sensor
#include <Arduino.h>
#include "SHTC3.h"
SHTC3 s(Wire);


//--Humid control
int v1;   // Humid Min
int v2;   // Humid Max
//--Temp control
int v3;   // Temp Min
int v4;   // Temp Max
WidgetLED led_1(V5);



//------------------------------------------------------------------------------------------------------------------------//
BLYNK_WRITE(V1)//  Humid Min  รับการตั้งค่ามาจาก Widget Vertical Slider ของ Blynk
{
  v1 = param.asInt();
}
//------------------------------------------------------------------------------------------------------------------------//
BLYNK_WRITE(V2)//  Humid Max  รับการตั้งค่ามาจาก Widget Vertical Slider ของ Blynk
{
  v2 = param.asInt();
}
//------------------------------------------------------------------------------------------------------------------------//
BLYNK_WRITE(V3)//  Temp Min   รับการตั้งค่ามาจาก Widget Vertical Slider ของ Blynk
{
  v3 = param.asInt();
}
//------------------------------------------------------------------------------------------------------------------------//
BLYNK_WRITE(V4)// Temp Max    รับการตั้งค่ามาจาก Widget Vertical Slider ของ Blynk
{
  v4 = param.asInt();
}
//------------------------------------------------------------------------------------------------------------------------//




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

void setup() {

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

  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);



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

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


  Serial.begin(115200);
  //-------------------------------//
  Wire.begin();
  LINE.setToken(LINE_TOKEN);



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

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

  if (SPIFFS.begin(true)) {
    Serial.println("mounted file system");
    if (SPIFFS.exists("/config.json")) {
      //file exists, reading and loading
      Serial.println("reading config file");
      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");
          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
  Serial.println(blynk_token);

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









  //**************************        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(Ledblynk, HIGH);
    delay(500);
    digitalWrite(Ledblynk, LOW);
    delay(500);
    Serial.print (String(i) + " ");//แสดงข้อความใน Serial Monitor
  }


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



    // wifiManager.resetSettings();//ให้ล้างค่า SSID และ Password ที่เคยบันทึกไว้
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); //load the flash-saved configs
    esp_wifi_init(&cfg); //initiate and allocate wifi resources (does not matter if connection fails)
    delay(2000); //wait a bit
    if (esp_wifi_restore() != ESP_OK)

    {
      Serial.println("WiFi is not initialized by esp_wifi_init ");
    } else {
      Serial.println("WiFi Configurations Cleared!");
    }
    //continue
    //delay(1000);
    //esp_restart(); //just my reset configs routine...


  }

  wifiManager.setTimeout(60);
  //ใช้ได้ 2 กรณี
  //1. เมื่อกดปุ่มเพื่อ Config ค่า AP แล้ว จะขึ้นชื่อ AP ที่เราตั้งขึ้น
  //   ช่วงนี้ให้เราทำการตั้งค่า SSID+Password หรืออื่นๆทั้งหมด ภายใน 60 วินาที ก่อน AP จะหมดเวลา
  //   ไม่เช่นนั้น เมื่อครบเวลา 60 วินาที MCU จะ Reset เริ่มต้นใหม่ ให้เราตั้งค่าอีกครั้งภายใน 60 วินาที
  //2. ช่วงไฟดับ Modem router + MCU จะดับทั้งคู่ และเมื่อมีไฟมา ทั้งคู่ก็เริ่มทำงานเช่นกัน
  //   โดยปกติ Modem router จะ Boot ช้ากว่า  MCU ทำให้ MCU กลับไปเป็น AP รอให้เราตั้งค่าใหม่
  //   ดังนั้น AP จะรอเวลาให้เราตั้งค่า 60 วินาที ถ้าไม่มีการตั้งค่าใดๆ เมื่อครบ 60 วินาที MCU จะ Reset อีกครั้ง
  //   ถ้า Modem router  Boot และใช้งานได้ภายใน 60 วินาที และหลังจากที่ MCU Resset และเริ่มทำงานใหม่
  //   ก็จะสามารถเชื่อมต่อกับ  Modem router ที่ Boot และใช้งานได้แล้ว  ได้  ระบบจะทำงานปกติ



  if (!wifiManager.autoConnect("PUYIOT ทดสอบ ESP32 ")) {
    Serial.println("failed to connect and hit timeout");//แสดงข้อความใน Serial Monitor
    delay(3000);
    //reset and try again, or maybe put it to deep sleep
    ESP.restart();//แก้ เดิม ESP.reset(); ใน Esp8266
    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");
    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

  //ตั้งเวลาส่งข้อมูลให้ Blynk Server ทุกๆ 30 วินาที


  //create a task that will be executed in the Task1code() function, with priority 1 and executed on core 0
  xTaskCreatePinnedToCore(
    Task1code,   /* Task function. */
    "Task1",     /* name of task. */
    10000,       /* Stack size of task */
    NULL,        /* parameter of the task */
    1,           /* priority of the task ตัวเลขน้อยสำคัญน้อย*/
    &Task1,      /* Task handle to keep track of created task */
    0);          /* pin task to core 0 */
  delay(500);











}//end void setup



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








//Task1_code
void Task1code( void * pvParameters ) {

  Serial.print("Task1 running on core ");
  Serial.println(xPortGetCoreID());
  int linenotify = 0;
  int linenotify1 = 0;
  int Temp;
  int Humid;
  //  Serial.println("viod setup");
  //  Serial.println(linenotify);



  for (;;) {

    s.begin(true);
    s.sample();
    temp = s.readTempC();
    humid = s.readHumidity();

    Blynk.virtualWrite(V7, s.readTempC());
    Blynk.virtualWrite(V8, s.readHumidity());
    delay(1500);

    //แยกว่า อุปกรณ์ทำงาน โดยเข้าเงื่อนไขของ Temp หรือ Humid ถ้าเข้าเงื่อนไขทั้งคู่ ก็ Line ส่งข้อความ 2 ครั้ง
    if  ( (temp > v3 && temp < v4) ) {
      Temp = 1;
    }
    else {
      Temp = 0;
    }
    delay(50);


    if ((linenotify == 0) && (Temp == 1) ) {

      //      led_1.on();
      String LineText;
      String string1 = "อุปกรณ์ทำงาน ตาม  Temp.    ที่ตั้งไว้ ";
      String string2 = "Temp (°C)";
      String string3 = "|";
      String string4 = "|";
      String string5 = "|";

      LineText = string1 + string2  +  string3 + v3 +  string4 + temp +  string5 + v4 ;
      LINE.notify(LineText);
      delay(200);
      linenotify = 1;
      //      Serial.println("if 1");
      //      Serial.println(linenotify);
    }

    if ((linenotify == 1) && (Temp == 1) ) {
      //      led_1.on();
      delay(30);
      //        Serial.println("if 2");
      //        Serial.println(linenotify);
    }


    if ((linenotify == 1) && (Temp == 0) ) {
      linenotify = 0;
      //        Serial.println("if 2");
      //        Serial.println(linenotify);
    }

    if ((linenotify == 0) && (Temp == 0) ) {
      //      led_1.off();
      linenotify = 0;
      //        Serial.println("if 2");
      //        Serial.println(linenotify);
    }

    delay(150);

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

    if  ( (humid > v1 && humid < v2) ) {
      Humid = 1;
    }
    else {
      Humid = 0;
    }
    delay(100);


    if ((linenotify1 == 0) && (Humid == 1) ) {


      //      led_1.on();
      String LineText;
      String string11 = "อุปกรณ์ทำงาน ตาม  Humid.   ที่ตั้งไว้ ";
      String string12 = "Humid (%)";
      String string13 = "|";
      String string14 = "|";
      String string15 = "|";

      LineText = string11 + string12  +  string13 + v1 +  string14 + humid +  string15 + v2 ;
      LINE.notify(LineText);
      delay(200);
      linenotify1 = 1;
      //      Serial.println("if 1");
      //      Serial.println(linenotify);
    }

    if ((linenotify1 == 1) && (Humid == 1) ) {
      //      led_1.on();
      //        Serial.println("if 2");
      //        Serial.println(linenotify);
    }


    if ((linenotify1 == 1) && (Humid == 0) ) {
      linenotify1 = 0;
      //        Serial.println("if 2");
      //        Serial.println(linenotify);
    }

    if ((linenotify1 == 0) && (Humid == 0) ) {
      //      led_1.off();
      linenotify1 = 0;
      //        Serial.println("if 2");
      //        Serial.println(linenotify);
    }

    delay(150);

    if ( (Temp == 1 && Humid == 1) or (Temp == 0 && Humid == 1) or (Temp == 1 && Humid == 0)  ) {
      led_1.on();
      delay(50);
    }
    else {
      led_1.off();
      delay(50);
    }







  }
}









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


void loop() {


  //-----------------------------------------------------------------------------------------------------------//
  if (Blynk.connected())
  {
    Blynk.run();
    digitalWrite(Ledblynk, HIGH);

  } else {

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

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

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

  delay(100);


}

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

ผมยังไม่เคยลองเล่นเลยครับพี่ :rofl:

ผมก็ยังไม่เคยเหมือนครับ

รออ่านนะครับพี่

รบกวนสอบถามเกี่ยวกับการ config line token หน่อยค่ะ

โจทย์คือไม่ต้องการให้ใส่หรือแก้ line token ผ่านทาง Code แต่ต้องการให้แยกหน้า Config ส่วนออกมา ประมาณว่าให้เปลี่ยนหรือแก้ไข line token ผ่านชื่องทางอื่นแทนจะสามารถทำได้ไหมค่ะ และหากสามารถทำได้รบกวนขอคำชี้แนะด้วยค่ะ

ขอบคุณค่ะ

หลักการเดียวกันกับกระทู้นี้ครับ

ผมก็ต้องการทำแบบนี้เหมือนกันครับ ถ้าทำได้แล้วรบกวนสอนด้วยนะครับ