Hi guys.
I am working on a project that requires me to connect to Blynk.Edgent, Firebase, and display the UI simultaneously. I am using ESP32 to program, and the LCD TFT I am using is the ILI9811. I have researched and found anything that related to my project, but i found nothing. So here I am.
The project involves collecting data from the fine dust sensor PMS5003, temperature, and humidity SHT31, displaying it on the screen, and pushing it to Firebase. However, I am unable to connect to Blynk cloud, even though I have already accessed the Wi-Fi network, and the Wi-Fi is running smoothly and the framework is Arduino btw.
At first, I suspected that the Wi-Fi connection with ESP32 was the problem. However, I tested it with ThingSpeak, and it ran smoothly without any delay. The ESP32 can connect to the ThingSpeak cloud.
Next, I tested to run the Blynk.Edgent alone, and it ran okay. The ESP32 can access the Blynk Cloud, and I can configure the Blynk configuration through my app Blynk on my iPhone. I still kept the RTOS configuration when I tested.
However, I am unable to understand why when I added the code of the UI with the Blynk.Edgent code, the expected result did not appear.
Note: I used lgvl library for the UI code, and Squareline studio to design the UI.
I will upload the code if you guy would like to take a look:
/*Don't forget to set Sketchbook location in File/Preferencesto the path of your UI project (the parent foder of this INO file)*/
#define BLYNK_TEMPLATE_ID ""
#define BLYNK_TEMPLATE_NAME ""
#define BLYNK_FIRMWARE_VERSION "0.1.1"
#define BLYNK_PRINT Serial
#define APP_DEBUG
#define USE_ESP32_DEV_MODULE
#include "BlynkEdgent.h"
#include <lvgl.h>
#include <TFT_eSPI.h>
#include <ui.h>
#include <PMserial.h>
#include <Wire.h>
#include "Wire.h"
#include "SHT31.h"
#include "ThingSpeak.h" // always include thingspeak header file after other header files and custom macros
#include <WiFiManager.h> // Include the WiFiManager library
#include <Arduino.h>
#include <WiFi.h>
#include <FirebaseESP32.h>
#include <addons/TokenHelper.h>
#include <addons/RTDBHelper.h>
/* Config UART pins with PMS5003 */
#if !defined(PMS_RX) && !defined(PMS_TX)
constexpr auto PMS_RX = 16;
constexpr auto PMS_TX = 17;
#endif
#ifndef ESP32
SerialPM pms(PMS5003, PMS_RX, PMS_TX); // PMSx003, RX, TX
#else
SerialPM pms(PMS5003, PMS_RX, PMS_TX); // PMSx003, RX, TX
#endif
/* Define ADC pin to read battery current */
#define BAT_LV1 2 // Power supply PIN for screen
#define BUTTON_PIN 0 // Button PIN
#define LEDA 14
/* Define address for SHT31 */
#define SHT31_ADDRESS 0x44
/* Define the API_KEY and DATABASE_URL for Firebase */
#define API_KEY ""
#define DATABASE_URL ""
/* define cores for CPU */
static const BaseType_t pro_cpu = 0;
static const BaseType_t app_cpu = 1;
/* Init tasks and task handle */
static TaskHandle_t taskReadValues;
static TaskHandle_t taskDisplayValueToScreen;
static TaskHandle_t taskButtonFunctions;
static TaskHandle_t taskRunUI;
static TaskHandle_t taskWifi;
static TaskHandle_t taskSendDataToFirebase;
static TaskHandle_t taskBlynkRun;
static TaskHandle_t taskBlynkInit;
void TaskReadValues(void *pvParameters);
void TaskDisplayValueToScreen(void *pvParameters);
void TaskButtonFunctions(void *pvParameters);
void TaskRunUI(void *pvParameters);
void TaskWifi(void *pvParameters);
void TaskSendDataToFirebase(void *pvParameters);
void TaskBlynkRun(void *pvParameters);
void TaskBlynkInit(void *pvParameters);
void ui_screen_1_reset();
void getAQIFromPM25();
int calculateAQI(float I_high, float I_low, float C_high, float C_low, float C);
/* Init variables for Sending data to firebase*/
FirebaseData fbdo;
FirebaseAuth auth;
FirebaseConfig config;
unsigned long sendDataPrevMillis = 0;
bool isSignup = false;
unsigned long count = 0;
unsigned long dataMillis = 0;
/* Init pms values, battery values and sh31 values */
int pms_pm1p0, pms_pm2p5, pms_pm10; // pms values
float battery_Value; // battery voltage
bool screenState = false; // Screen state
float battery_Percentage; // % battery
int temp; // temperature
int humi; // humidity
/* Define for change screen tasks */
const unsigned long longPressTime = 2000; // how long the button needs to be pressed for long press (in milliseconds)
bool screenToggled = false; // whether the SCREEN has been toggled
int lastButtonState = HIGH; // the previous reading from the input pin
int counter = 1; // counter for the number of button presses
unsigned long buttonPressTime; // when the button was pressed
bool resetWifiState = false;
int timeout = 120; // seconds to run for
/*Change to your screen resolution*/
static const uint16_t screenWidth = 320;
static const uint16_t screenHeight = 240;
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[screenWidth * screenHeight / 10];
TFT_eSPI tft = TFT_eSPI(screenWidth, screenHeight); /* TFT instance */
SHT31 sht;
WiFiManager wm;
WiFiClient client;
/* Display flushing */
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) {
uint32_t w = (area->x2 - area->x1 + 1);
uint32_t h = (area->y2 - area->y1 + 1);
tft.startWrite();
tft.setAddrWindow(area->x1, area->y1, w, h);
tft.pushColors((uint16_t *)&color_p->full, w * h, true);
tft.endWrite();
lv_disp_flush_ready(disp);
}
/*Read the touchpad*/
void my_touchpad_read(lv_indev_drv_t *indev_driver, lv_indev_data_t *data) {
uint16_t touchX = 0, touchY = 0;
bool touched = false; //tft.getTouch( &touchX, &touchY, 600 );
if (!touched) {
data->state = LV_INDEV_STATE_REL;
} else {
data->state = LV_INDEV_STATE_PR;
/*Set the coordinates*/
data->point.x = touchX;
data->point.y = touchY;
Serial.print("Data x ");
Serial.println(touchX);
Serial.print("Data y ");
Serial.println(touchY);
}
}
void setup() {
Serial.begin(115200); /* prepare for possible serial debug */
lv_init();
tft.begin(); /* TFT init */
tft.setRotation(1); /* Landscape orientation, flipped */
lv_disp_draw_buf_init(&draw_buf, buf, NULL, screenWidth * screenHeight / 10);
/*Initialize the display*/
static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
/*Change the following line to your display resolution*/
disp_drv.hor_res = screenWidth;
disp_drv.ver_res = screenHeight;
disp_drv.flush_cb = my_disp_flush;
disp_drv.draw_buf = &draw_buf;
lv_disp_drv_register(&disp_drv);
/*Initialize the (dummy) input device driver*/
static lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = my_touchpad_read;
lv_indev_drv_register(&indev_drv);
ui_init(); // UI Screen init
ui_screen_1_reset(); // Reset all values in UI Screen
pms.init(); // init PMS5003
Wire.begin();
sht.begin(SHT31_ADDRESS); // init SHT31
/* Init pins */
pinMode(BUTTON_PIN, INPUT_PULLUP);
// pinMode(BAT_LV1, OUTPUT);
pinMode(LEDA, OUTPUT);
digitalWrite(LEDA, HIGH);
delay(100);
/* Init tasks */
Serial.print("HEAP size left: ");
Serial.println(ESP.getFreeHeap());
// Task funct - taks name - stack size - parameters - task handle - core to run on
xTaskCreatePinnedToCore(TaskRunUI, "RunningUI", 10000, NULL, 5, &taskRunUI, app_cpu);
xTaskCreatePinnedToCore(TaskButtonFunctions, "TurnOnOff_or_ChangeScreen_or_Configwifi", 10000, NULL, 4, &taskButtonFunctions, app_cpu);
xTaskCreatePinnedToCore(TaskDisplayValueToScreen, "DisplayValueToScreen", 8000, NULL, 4, &taskDisplayValueToScreen, app_cpu);
xTaskCreatePinnedToCore(TaskReadValues, "ReadValues", 5000, NULL, 3, &taskReadValues, app_cpu);
// xTaskCreatePinnedToCore(TaskWifi, "Wifi", 10000, NULL, 2, &taskWifi, app_cpu);
xTaskCreatePinnedToCore(TaskBlynkInit, "BlynkInit", 5000, NULL, 2, &taskBlynkInit, pro_cpu);
xTaskCreatePinnedToCore(TaskBlynkRun, "BlynkRun", 10000, NULL, 1, &taskBlynkRun, pro_cpu);
xTaskCreatePinnedToCore(TaskSendDataToFirebase, "ConnectSendDataToFirebase", 10000, NULL, 1, &taskSendDataToFirebase, app_cpu);
Serial.println("Setup done");
vTaskDelete(NULL); // delete setup and loop after setup is done
}
void loop() {
// Do nothing in loop
}
void TaskRunUI(void *pvParameters) {
while (1) {
lv_timer_handler(); /* let the GUI do its work */
vTaskDelay(10 / portTICK_PERIOD_MS);
}
}
void TaskBlynkInit(void *pvParameters) {
BlynkEdgent.begin();
vTaskDelete(NULL); // delete after done
}
void TaskBlynkRun(void *pvParameters) {
while (1) {
BlynkEdgent.run();
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
void TaskSendDataToFirebase(void *pvParameters) {
config.api_key = API_KEY;
/* Assign the RTDB URL (required) */
config.database_url = DATABASE_URL;
/* Assign the callback function for the long running token generation task */
config.token_status_callback = tokenStatusCallback; // see addons/TokenHelper.h
// Comment or pass false value when WiFi reconnection will control by your code or third party library e.g. WiFiManager
Firebase.reconnectNetwork(true);
// Since v4.4.x, BearSSL engine was used, the SSL buffer need to be set.
// Large data transmission may require larger RX buffer, otherwise connection issue or data read time out can be occurred.
fbdo.setBSSLBufferSize(4096 /* Rx buffer size in bytes from 512 - 16384 */, 1024 /* Tx buffer size in bytes from 512 - 16384 */);
// Or use legacy authenticate method
// config.database_url = DATABASE_URL;
config.signer.tokens.legacy_token = "";
// Please make sure the device free Heap is not lower than 80 k for ESP32 and 10 k for ESP8266,
// otherwise the SSL connection will fail.
config.timeout.serverResponse = 1 * 1000; // config the server respone back is 1 sec
Firebase.begin(&config, &auth);
while (1) {
String pms_pm1p0_value = (String)pms_pm1p0;
String pms_pm2p5_value = (String)pms_pm2p5;
String pms_pm10_value = (String)pms_pm10;
int aqi_value = getAQIFromPM25(pms.pm25);
String celsius_value = (String)temp;
String rh_value = (String)humi;
if ((millis() - dataMillis > 5000) && Firebase.ready()) {
dataMillis = millis();
// Serial.printf("Set int... %s\n", Firebase.setInt(fbdo, "/test", count++) ? "ok" : fbdo.errorReason().c_str());
Serial.printf("Set str... %s\n", Firebase.setString(fbdo, "/temp", celsius_value) ? "ok" : fbdo.errorReason().c_str());
Serial.printf("Set str... %s\n", Firebase.setString(fbdo, "/pm1p0", pms_pm1p0_value) ? "ok" : fbdo.errorReason().c_str());
Serial.printf("Set str... %s\n", Firebase.setString(fbdo, "/pm2p5", pms_pm2p5_value) ? "ok" : fbdo.errorReason().c_str());
Serial.printf("Set str... %s\n", Firebase.setString(fbdo, "/pm10", pms_pm10_value) ? "ok" : fbdo.errorReason().c_str());
Serial.printf("Set int... %s\n", Firebase.setInt(fbdo, "/aqi", aqi_value) ? "ok" : fbdo.errorReason().c_str());
Serial.printf("Set str... %s\n", Firebase.setString(fbdo, "/humi", rh_value) ? "ok" : fbdo.errorReason().c_str());
Serial.println(ESP.getFreeHeap());
}
vTaskDelay(200 / portTICK_PERIOD_MS);
}
}
void ui_screen_1_reset() {
lv_label_set_text(ui_pm2p5ValueLabel, "0"); // update pm2.5 label to 0
lv_label_set_text(ui_pm1p0ValueLabel, "0"); // update pm1.0 label to 0
lv_label_set_text(ui_pm10ValueLabel, "0"); // update pm10 label to 0
lv_slider_set_value(ui_aqiSlider, 0, LV_ANIM_OFF); // update aqi slider value to 0
lv_label_set_text(ui_aqiValueLabel, "0"); // update aqi label to 0
lv_label_set_text(ui_batteryPercentageValueLabel1, "0"); // update battery label value to 0
lv_slider_set_value(ui_batterySlider1, 0, LV_ANIM_OFF); // update battery slider value to 0
}
void TaskButtonFunctions(void *pvParameters) {
while (1) {
// read the state of the pushbutton value:
int currentButtonState = digitalRead(BUTTON_PIN);
// check for button press
if (lastButtonState == HIGH && currentButtonState == LOW) {
buttonPressTime = millis();
screenToggled = false;
resetWifiState = false;
}
// check for long press
else if (currentButtonState == LOW && !screenToggled && millis() - buttonPressTime > longPressTime) {
digitalWrite(LEDA, !digitalRead(LEDA)); // toggle the LED
screenToggled = true;
} else if (currentButtonState == LOW && !resetWifiState && digitalRead(LEDA) != LOW && millis() - buttonPressTime > 5000) { // when the screen is off, you can not reset the wifi
// digitalWrite(LEDA, !digitalRead(LEDA)); // toggle the LED
resetWifiState = true;
// wm.resetSettings();
// set configportal timeout
wm.setConfigPortalTimeout(120); // set the timeout for 30secs
if (!wm.startConfigPortal("AirSensor")) {
Serial.println("failed to connect and hit timeout");
vTaskDelay(5000 / portTICK_PERIOD_MS);
// //reset and try again, or maybe put it to deep sleep
ESP.restart();
// delay(5000);
vTaskDelay(5000 / portTICK_PERIOD_MS);
}
//if you get here you have connected to the WiFi
Serial.println("connected...yeey :)");
}
// check for button release
else if (lastButtonState == LOW && currentButtonState == HIGH) {
if (!screenToggled) {
if (counter == 1) {
_ui_screen_change(&ui_airSensorScreen2, LV_SCR_LOAD_ANIM_FADE_ON, 400, 0, &ui_airSensorScreen2_screen_init);
} else {
_ui_screen_change(&ui_airSensorScreen1, LV_SCR_LOAD_ANIM_FADE_ON, 400, 0, &ui_airSensorScreen1_screen_init);
}
//reset the counter
counter = 3 - counter;
}
}
// save the current state as the last state,
// for next time through the loop
lastButtonState = currentButtonState;
// delay a little bit to avoid bouncing
vTaskDelay(50 / portTICK_PERIOD_MS);
}
}
void TaskDisplayValueToScreen(void *pvParameters) {
while (1) {
String pms_pm1p0_label_value = (String)pms_pm1p0;
String pms_pm2p5_label_value = (String)pms_pm2p5;
String pms_pm10_label_value = (String)pms_pm10;
int aqi_Slider_Value = getAQIFromPM25(pms.pm25);
String aqi_label_value = (String)aqi_Slider_Value;
String battery_percentage_label_value = (String)((int)battery_Percentage);
int battery_slider_value = (int)(battery_Percentage);
String celsius_label_value = (String)temp;
String rh_label_value = (String)humi;
/* Screen 1 */
lv_label_set_text(ui_pm1p0ValueLabel, pms_pm1p0_label_value.c_str()); // update pm1.0 label value in screen 1
lv_label_set_text(ui_pm2p5ValueLabel, pms_pm2p5_label_value.c_str()); // update pm2.5 label value in screen 1
lv_label_set_text(ui_pm10ValueLabel, pms_pm10_label_value.c_str()); // update pm10 label value in screen 1
lv_slider_set_value(ui_aqiSlider, aqi_Slider_Value, LV_ANIM_OFF); // update aqi slider value in screen 1
lv_label_set_text(ui_aqiValueLabel, aqi_label_value.c_str()); // update aqi label value in screen 1
lv_label_set_text(ui_batteryPercentageValueLabel1, battery_percentage_label_value.c_str()); // update battery label value in screen 1
lv_slider_set_value(ui_batterySlider1, battery_slider_value, LV_ANIM_OFF); // update battery slider value in screen 1
/* Screen 2 */
lv_label_set_text(ui_batteryPercentageValueLabel2, battery_percentage_label_value.c_str()); // update battery label value in screen 2
lv_slider_set_value(ui_batterySlider2, battery_slider_value, LV_ANIM_OFF); // update battery slider value in screen 2
lv_label_set_text(ui_degreeCelsiusValueLabel, celsius_label_value.c_str()); // update celsius label value in screen 2
lv_label_set_text(ui_rhValueLabel, rh_label_value.c_str()); // update humindity label value in screen 2
lv_label_set_text(ui_soundValueLabel, "100"); // update noise label value in screen 2
lv_label_set_text(ui_tvocValueLabel, "0.000"); // update tvoc label value in screen 2
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
void TaskReadValues(void *pvParameters) {
while (1) {
pms.read();
sht.read();
// if (pms) {
/* Read pms */
pms_pm1p0 = pms.pm01;
pms_pm2p5 = pms.pm25;
pms_pm10 = pms.pm10;
// }
/* Read battery's voltage */
int battery = analogRead(BAT_LV1);
float battery_Test = (3.41111 * (float)battery) / 4095;
float battery_Test_2 = (battery_Test / 2700) * 3700;
float baterry_V_Max = 4.2;
battery_Percentage = round((battery_Test_2 / baterry_V_Max) * 100);
/* Read sht values */
float t = sht.getTemperature();
float h = sht.getHumidity();
temp = (int)round(t);
humi = (int)round(h);
vTaskDelay(50 / portTICK_PERIOD_MS);
}
}
// Function to calculate AQI
int calculateAQI(float I_high, float I_low, float C_high, float C_low, float C) {
return ((I_high - I_low) / (C_high - C_low)) * (C - C_low) + I_low;
}
// Function that get the AQI from PM2.5
int getAQIFromPM25(float pm25) {
if (pm25 <= 12.0) {
return calculateAQI(50, 0, 12.0, 0.0, pm25);
} else if (pm25 <= 35.4) {
return calculateAQI(100, 51, 35.4, 12.1, pm25);
} else if (pm25 <= 55.4) {
return calculateAQI(150, 101, 55.4, 35.5, pm25);
} else if (pm25 <= 150.4) {
return calculateAQI(200, 151, 150.4, 55.5, pm25);
} else if (pm25 <= 250.4) {
return calculateAQI(300, 201, 250.4, 150.5, pm25);
} else if (pm25 <= 350.4) {
return calculateAQI(400, 301, 350.4, 250.5, pm25);
} else if (pm25 <= 500.4) {
return calculateAQI(500, 401, 500.4, 350.5, pm25);
} else {
// PM2.5 value is off the charts; return -1 to indicate error
return -1;
}
}