#define BOARD_ID adafruit_qtpy_esp32s2
// THIS WONT BUILD WITHOUT PRIVATE SERVER, EVEN WITH ASSETS REMOVED.
// It's "just" under 1megabyte in code + assets
#define WOKWI 1
//Currently setup to use lilygo TDisplayS3 (320x170) which uses intel8080 parallel interface to ST7789 driver.
//Will be re-written to use ILI9341 (320x240 screen) and FT6206 touch IC
// Set filesystem to >2MB app, currently designed for T-Display-S3 16MB flash 8mb PSRAM (OPI)
#define DEBUG 0 // Set to 1 to wait for serial before starting routine...
// NB: send enter in serial monitor to begin
#include "Arduino.h"
#include "OneButton.h"
#include "WiFi.h"
#include "cstxx.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_vendor.h"
#include "factory_gui.h"
#include "lvgl.h"
#include "pin_config.h"
#include "sntp.h"
#include "time.h"
#include "sdkconfig.h"
#include "ui.h"
#define LV_DELAY(x) \
do { \
uint32_t t = x; \
while (t--) { \
lv_timer_handler(); \
button1.tick(); \
button2.tick(); \
delay(1); \
} \
} while (0);
void ui_init(void);
esp_lcd_panel_io_handle_t io_handle = NULL;
static lv_disp_draw_buf_t disp_buf; // contains internal graphic buffer(s) called draw buffer(s)
static lv_disp_drv_t disp_drv; // contains callback functions
static lv_color_t *lv_disp_buf;
static bool is_initialized_lvgl = false;
OneButton button1(PIN_BUTTON_1, true);
OneButton button2(PIN_BUTTON_2, true);
CSTXXX touch(0, 0, 170, 320);
bool SKIP_CURRENT = 0;
bool inited_touch = false;
struct wifi {
String ssid;
String password;
byte rssi;
} cred1,cred2,cred3,cred4;
//Good-enough for now : Look at wifimanager library, or me-no-dev/ASyncWebServer etc
struct wifi Wifis[4];
int topRSSI=-1000;
wifi chosenWifi;
extern String WifiTemplateStringSTA =
"Wifi Connected\nConnected AP:\nssid: {ssid}\nquality: -45db\nip: {ip}\n\nHelpful QRCode to\njoin wifi then visit\nhttp://{ip}\nin web browser";
extern String WifiTemplateStringAP =
"Wifi Connected\nBroadcasting AP:\nssid: {ssid}\npw: {pass}\nip: {ip}\n\nHelpful QRCode to\njoin wifi then visit\nhttp://{ip}\nin web browser";
extern const unsigned char img_logo[];
void wifi_test(void);
void timeavailable(struct timeval *t);
void printLocalTime();
void SmartConfig();
static bool example_notify_lvgl_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx) {
if (is_initialized_lvgl) {
lv_disp_drv_t *disp_driver = (lv_disp_drv_t *)user_ctx;
lv_disp_flush_ready(disp_driver);
}
return false;
}
static void example_lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) {
esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t)drv->user_data;
int offsetx1 = area->x1;
int offsetx2 = area->x2;
int offsety1 = area->y1;
int offsety2 = area->y2;
// copy a buffer's content to a specific area of the display
esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map);
}
void setup() {
cred1.ssid="free4all_2G";
cred1.password="password";
cred2.ssid="Tenda_60C06C";
cred2.password="south5358";
cred3.ssid="NETGEAR94";
cred3.password="classytuba580";
cred4.ssid="SENSOR-NET";
cred4.password="password";
Wifis[0]=cred1;
Wifis[1]=cred2;
Wifis[2]=cred3;
Wifis[3]=cred4;
chosenWifi.ssid = WIFI_SSID;
chosenWifi.password = WIFI_PASSWORLD; // Default misspelt example WIFI_PASSWORD from factory.ino/pin_config.h
pinMode(PIN_POWER_ON, OUTPUT);
digitalWrite(PIN_POWER_ON, HIGH);
Serial.begin(115200);
#if(DEBUG==1)
while(!Serial.available())
LV_DELAY(10);
#endif
Serial.println("Default wifi:");
Serial.println(WIFI_SSID);
sntp_servermode_dhcp(1); // (optional)
//configTime(GMT_OFFSET_SEC, DAY_LIGHT_OFFSET_SEC, NTP_SERVER1, NTP_SERVER2);
configTzTime(TIMEZONE, NTP_SERVER1, NTP_SERVER2);
#pragma region I8080 setup
pinMode(PIN_LCD_RD, OUTPUT);
digitalWrite(PIN_LCD_RD, HIGH);
esp_lcd_i80_bus_handle_t i80_bus = NULL;
esp_lcd_i80_bus_config_t bus_config = {
.dc_gpio_num = PIN_LCD_DC,
.wr_gpio_num = PIN_LCD_WR,
.clk_src = LCD_CLK_SRC_PLL160M,
.data_gpio_nums =
{
PIN_LCD_D0,
PIN_LCD_D1,
PIN_LCD_D2,
PIN_LCD_D3,
PIN_LCD_D4,
PIN_LCD_D5,
PIN_LCD_D6,
PIN_LCD_D7,
},
.bus_width = 8,
.max_transfer_bytes = LVGL_LCD_BUF_SIZE * sizeof(uint16_t),
};
esp_lcd_new_i80_bus(&bus_config, &i80_bus);
esp_lcd_panel_io_i80_config_t io_config = {
.cs_gpio_num = PIN_LCD_CS,
.pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
.trans_queue_depth = 20,
.on_color_trans_done = example_notify_lvgl_flush_ready,
.user_ctx = &disp_drv,
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
.dc_levels =
{
.dc_idle_level = 0,
.dc_cmd_level = 0,
.dc_dummy_level = 0,
.dc_data_level = 1,
},
};
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle));
esp_lcd_panel_handle_t panel_handle = NULL;
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = PIN_LCD_RES,
.color_space = ESP_LCD_COLOR_SPACE_RGB,
.bits_per_pixel = 16,
};
esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle);
esp_lcd_panel_reset(panel_handle);
esp_lcd_panel_init(panel_handle);
esp_lcd_panel_invert_color(panel_handle, true);
esp_lcd_panel_swap_xy(panel_handle, true);
esp_lcd_panel_mirror(panel_handle, false, true);
// the gap is LCD panel specific, even panels with the same driver IC, can
// have different gap value
esp_lcd_panel_set_gap(panel_handle, 0, 35);
#pragma endregion I8080 setup
#pragma region lvgl init
lv_init();
lv_disp_buf = (lv_color_t *)heap_caps_malloc(LVGL_LCD_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
lv_disp_draw_buf_init(&disp_buf, lv_disp_buf, NULL, LVGL_LCD_BUF_SIZE);
/*Initialize the display*/
lv_disp_drv_init(&disp_drv);
/*Change the following line to your display resolution*/
disp_drv.hor_res = EXAMPLE_LCD_H_RES;
disp_drv.ver_res = EXAMPLE_LCD_V_RES;
disp_drv.flush_cb = example_lvgl_flush_cb;
disp_drv.draw_buf = &disp_buf;
disp_drv.user_data = panel_handle;
lv_disp_drv_register(&disp_drv);
is_initialized_lvgl = true;
#pragma endregion lvgl init
Serial.println("Lcd init");
/* Lighten the screen with gradient */
ledcSetup(0, 10000, 8);
ledcAttachPin(PIN_LCD_BL, 0);
for (uint8_t i = 0; i < 0xFF; i++) {
ledcWrite(0, i);
LV_DELAY(10);
}
Wire.begin(PIN_IIC_SDA, PIN_IIC_SCL);
inited_touch = touch.init(Wire, PIN_TOUCH_RES, PIN_TOUCH_INT);
button1.attachDoubleClick([]() {
SKIP_CURRENT = true;
Serial.println("Specifying skip");
});
wifi_test();
button1.reset();
button1.attachClick([]() {
pinMode(PIN_POWER_ON, OUTPUT);
pinMode(PIN_LCD_BL, OUTPUT);
digitalWrite(PIN_POWER_ON, LOW);
digitalWrite(PIN_LCD_BL, LOW);
// Reset wifi to avoid reconnect issues
WiFi.disconnect();
WiFi.mode(WIFI_OFF);
esp_sleep_enable_ext0_wakeup((gpio_num_t)PIN_BUTTON_2, 0); // 1 = High, 0 = Low
esp_deep_sleep_start();
});
button2.attachClick([]() { ui_switch_page(); });
button2.attachLongPressStop([](){
button1.reset();
button2.reset();
button1.attachClick([](){
Serial.println("btn1");
ESP.restart();
});
button2.attachClick([](){
Serial.println("btn2");
ESP.restart();
});
ui_init();
});
}
bool isKnown(String ssid, int rssi){
int n = sizeof(Wifis) / sizeof(*Wifis);
for (int i = 0; i < n; ++i) {
if(Wifis[i].ssid == ssid){
Serial.println("found known network");
if(rssi >= topRSSI){
topRSSI = rssi;
chosenWifi = Wifis[i];
}
return true;
}
}
return false;
}
void loop() {
// lv_timer_handler();
// button1.tick();
// button2.tick();
LV_DELAY(1);
static uint32_t last_tick;
if (millis() - last_tick > 100) {
struct tm timeinfo;
if (getLocalTime(&timeinfo)) {
lv_msg_send(MSG_NEW_HOUR, &timeinfo.tm_hour);
lv_msg_send(MSG_NEW_MIN, &timeinfo.tm_min);
}
uint32_t volt = (analogRead(PIN_BAT_VOLT) * 2 * 3.3 * 1000) / 4096;
lv_msg_send(MSG_NEW_VOLT, &volt);
if (inited_touch) {
touch_info_t t;
String str_buf;
static uint8_t last_finger;
touch.get_touch_point(&t);
str_buf += " Finger num :";
str_buf += t.finger_num;
str_buf += " \n";
for (uint8_t i = 0; i < t.finger_num; i++) {
str_buf += "x:";
str_buf += t.point[i].x;
str_buf += " y:";
str_buf += t.point[i].y;
str_buf += " p:";
str_buf += t.point[i].pressure;
str_buf += " \n";
}
lv_msg_send(MSG_NEW_TOUCH_POINT, str_buf.c_str());
}
last_tick = millis();
}
}
LV_IMG_DECLARE(good_enough_final);
void wifi_test(void) {
String text;
lv_obj_t *logo_img = lv_gif_create(lv_scr_act());
lv_obj_center(logo_img);
lv_gif_set_src(logo_img, &good_enough_final);
int delayCount = 0;
SKIP_CURRENT=false;
while(delayCount<480 && !SKIP_CURRENT){
LV_DELAY(10);
delayCount++;
}
SKIP_CURRENT=false;
lv_obj_del(logo_img);
ui_init();
LV_DELAY(1000)
//
// lv_obj_t *log_label = lv_label_create(lv_scr_act());
// lv_obj_align(log_label, LV_ALIGN_TOP_LEFT, 0, 0);
// lv_obj_set_width(log_label, LV_PCT(100));
lv_textarea_set_text(ui_Screen2_TextArea1, "Scanning WiFi");
// lv_label_set_long_mode(ui_Screen2_TextArea1, LV_LABEL_LONG_SCROLL);
lv_label_set_recolor(ui_Screen2_TextArea1, true);
LV_DELAY(1);
// Reset wifi to avoid reconnect issues
WiFi.disconnect();
WiFi.mode(WIFI_OFF);
LV_DELAY(100);
WiFi.mode(WIFI_STA);
LV_DELAY(100);
int n = WiFi.scanNetworks();
Serial.println("scan done");
if (n == 0) {
text = "no networks found";
} else {
text = n;
text += " networks found\n";
for (int i = 0; i < n; ++i) {
text += (i + 1);
text += ": ";
text += WiFi.SSID(i);
text += " (";
text += WiFi.RSSI(i);
text += ")";
text += (WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? " OPEN" : " PWD";
if(isKnown(WiFi.SSID(i), WiFi.RSSI(i))){
text += " (Known)";
}
text += "\n";
delay(10);
}
}
LV_DELAY(250)
lv_textarea_set_text(ui_Screen2_TextArea1, text.c_str());
Serial.println(text);
LV_DELAY(500);
text += "Connecting to ";
Serial.print("Connecting to ");
text += chosenWifi.ssid;
text += "\n";
Serial.print(chosenWifi.ssid);
WiFi.begin(chosenWifi.ssid.c_str(), chosenWifi.password.c_str());
uint32_t last_tick = millis();
uint32_t i = 0;
bool is_smartconfig_connect = false;
// lv_label_set_long_mode(log_label, LV_LABEL_LONG_WRAP);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
text += ".";
lv_textarea_set_text(ui_Screen2_TextArea1, text.c_str());
LV_DELAY(10);
if (millis() - last_tick > WIFI_CONNECT_WAIT_MAX) { /* Automatically start smartconfig when connection times out */
text += "\nConnection timed out, start smartconfig";
lv_textarea_set_text(ui_Screen2_TextArea1, text.c_str());
LV_DELAY(100);
is_smartconfig_connect = true;
WiFi.mode(WIFI_AP_STA);
Serial.println("\r\n wait for smartconfig....");
text += "\r\n wait for smartconfig....";
text += "\nPlease use EspTouch Apps to connect to the distribution network";
lv_textarea_set_text(ui_Screen2_TextArea1, text.c_str());
WiFi.beginSmartConfig();
while (1) {
LV_DELAY(100);
if (WiFi.smartConfigDone()) {
Serial.println("\r\nSmartConfig Success\r\n");
Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str());
Serial.printf("PSW:%s\r\n", WiFi.psk().c_str());
text += "\nSmartConfig Success";
text += "\nSSID:";
text += WiFi.SSID().c_str();
text += "\nPSW:";
text += WiFi.psk().c_str();
lv_textarea_set_text(ui_Screen2_TextArea1, text.c_str());
LV_DELAY(1000);
last_tick = millis();
break;
}
}
}
}
if (!is_smartconfig_connect) {
text += "\nCONNECTED \nTakes ";
Serial.print("\n CONNECTED \nTakes ");
text += millis() - last_tick;
Serial.print(millis() - last_tick);
text += " ms\n";
Serial.println(" millseconds");
lv_textarea_set_text(ui_Screen2_TextArea1, text.c_str());
}
LV_DELAY(2000);
ui_begin();
}
void printLocalTime() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("No time available (yet)");
return;
}
Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
}
///////////////////////////////////////////////////
///////////////////////////////////////////////////
///////////////////////////////////////////////////
// #include <Wippersnapper.h>
// #include <WiFi.h>
// #include <HTTPClient.h>
// #include <ArduinoJson.h>
// #include <Adafruit_GFX.h>
// #include <Adafruit_ILI9341.h>
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// #define BTN_PIN 5
// #define TFT_DC 2
// #define TFT_CS 15
// Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// const String url = "https://v2.jokeapi.dev/joke/Programming";
// String getJoke() {
// HTTPClient http;
// http.useHTTP10(true);
// http.begin(url);
// http.GET();
// String result = http.getString();
// DynamicJsonDocument doc(2048);
// DeserializationError error = deserializeJson(doc, result);
// // Test if parsing succeeds.
// if (error) {
// Serial.print("deserializeJson() failed: ");
// Serial.println(error.c_str());
// return "<error>";
// }
// String type = doc["type"].as<String>();
// String joke = doc["joke"].as<String>();
// String setup = doc["setup"].as<String>();
// String delivery = doc["delivery"].as<String>();
// http.end();
// return type.equals("single") ? joke : setup + " " + delivery;
// }
// void nextJoke() {
// tft.setTextColor(ILI9341_WHITE);
// tft.println("\nLoading joke...");
// String joke = getJoke();
// tft.setTextColor(ILI9341_GREEN);
// tft.println(joke);
// }
// void setup() {
// pinMode(BTN_PIN, INPUT_PULLUP);
// WiFi.begin(ssid, password, 6);
// tft.begin();
// tft.setRotation(1);
// tft.setTextColor(ILI9341_WHITE);
// tft.setTextSize(2);
// tft.print("Connecting to WiFi");
// while (WiFi.status() != WL_CONNECTED) {
// delay(100);
// tft.print(".");
// }
// tft.print("\nOK! IP=");
// tft.println(WiFi.localIP());
// nextJoke();
// }
// void loop() {
// if (digitalRead(BTN_PIN) == LOW) {
// tft.fillScreen(ILI9341_BLACK);
// tft.setCursor(0, 0);
// nextJoke();
// }
// delay(100);
// }