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 ผ่านชื่องทางอื่นแทนจะสามารถทำได้ไหมค่ะ และหากสามารถทำได้รบกวนขอคำชี้แนะด้วยค่ะ

ขอบคุณค่ะ

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

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

ค่าความสำคัญสุดของtaskนี่สูงสุดเท่าไรครับ ของผมใช้esp32 ver 1.0.3ในexample มันใส่มาสูงสุดแค่2

ถ้าเป็น ESP8266 ที่ใช้ Library ESP8266Scheduler ใช้ได้ ประมาณ 6 Task ก็ Lowmemory แล้วครับ ส่วน ESP32 ผมลองดูแล้วค้อนข้างมีปัญหากับอุปกรณ์ที่มาต่อร่วมครับ ก็เลยพักไว้ก่อน