diff --git a/.gitignore b/.gitignore index 02e648b88..d59e422e6 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ node_modules .idea .direnv +wled-update.sh \ No newline at end of file diff --git a/usermods/ST7789_display/README.md b/usermods/ST7789_display/README.md index 653fdd752..f98dcf54e 100644 --- a/usermods/ST7789_display/README.md +++ b/usermods/ST7789_display/README.md @@ -2,11 +2,14 @@ This usermod allow to use 240x240 display to display following: +* current date and time; * Network SSID; * IP address; +* WiFi signal strength; * Brightness; * Chosen effect; * Chosen palette; +* effect speed and intensity; * Estimated current in mA; ## Hardware @@ -46,27 +49,29 @@ Add lines to section: default_envs = esp32dev build_flags = ${common.build_flags_esp32} -D USERMOD_ST7789_DISPLAY - + -DUSER_SETUP_LOADED=1 + -DST7789_DRIVER=1 + -DTFT_WIDTH=240 + -DTFT_HEIGHT=240 + -DCGRAM_OFFSET=1 + -DTFT_MOSI=21 + -DTFT_SCLK=22 + -DTFT_DC=27 + -DTFT_RST=26 + -DTFT_BL=14 + -DLOAD_GLCD=1 + ;optional for WROVER + ;-DCONFIG_SPIRAM_SUPPORT=1 ``` Save the `platformio.ini` file. Once this is saved, the required library files should be automatically downloaded for modifications in a later step. ### TFT_eSPI Library Adjustments -We need to modify a file in the `TFT_eSPI` library. If you followed the directions to modify and save the `platformio.ini` file above, the `User_Setup_Select.h` file can be found in the `/.pio/libdeps/esp32dev/TFT_eSPI` folder. +If you are not using PlatformIO you need to modify a file in the `TFT_eSPI` library. If you followed the directions to modify and save the `platformio.ini` file above, the `Setup24_ST7789.h` file can be found in the `/.pio/libdeps/esp32dev/TFT_eSPI/User_Setups/` folder. -Modify the `User_Setup_Select.h` file as follows: +Edit `Setup_ST7789.h` file and uncomment nad changep GPIO pin numbers in lines containing `TFT_MOSI`, `TFT_SCLK`, `TFT_RST`, `TFT_DC`. -* Comment out the following line (which is the 'default' setup file): +Modify the `User_Setup_Select.h` by uncommentig the line containing `#include ` and commenting out line containing `#include `. -```ini -//#include // Default setup is root library folder -``` - -* Add following line: - -```ini -#include // Setup file for ESP32 ST7789V SPI bus TFT -``` - -* Copy file `"Setup_ST7789_Display.h"` from usermod folder to `/.pio/libdeps/esp32dev/TFT_eSPI/User_Setups` +If your display includes backlight enable pin, #define TFT_BL with backlight enable GPIO number. \ No newline at end of file diff --git a/usermods/ST7789_display/ST7789_display.h b/usermods/ST7789_display/ST7789_display.h index bd501d08f..ae8f31f0d 100644 --- a/usermods/ST7789_display/ST7789_display.h +++ b/usermods/ST7789_display/ST7789_display.h @@ -7,27 +7,48 @@ #include #include -#define USERMOD_ST7789_DISPLAY 97 - -#ifndef TFT_DISPOFF -#define TFT_DISPOFF 0x28 +#ifndef USER_SETUP_LOADED + #ifndef ST7789_DRIVER + #error Please define ST7789_DRIVER + #endif + #ifndef TFT_WIDTH + #error Please define TFT_WIDTH + #endif + #ifndef TFT_HEIGHT + #error Please define TFT_HEIGHT + #endif + #ifndef TFT_MOSI + #error Please define TFT_MOSI + #endif + #ifndef TFT_SCLK + #error Please define TFT_SCLK + #endif + #ifndef TFT_DC + #error Please define TFT_DC + #endif + #ifndef TFT_RST + #error Please define TFT_RST + #endif + #ifndef LOAD_GLCD + #error Please define LOAD_GLCD + #endif +#endif +#ifndef TFT_BL + #define TFT_BL -1 #endif -#ifndef TFT_SLPIN -#define TFT_SLPIN 0x10 -#endif +#define USERMOD_ID_ST7789_DISPLAY 97 -#define TFT_MOSI 21 -#define TFT_SCLK 22 -#define TFT_DC 18 -#define TFT_RST 5 -#define TFT_BL 26 // Display backlight control pin +TFT_eSPI tft = TFT_eSPI(TFT_WIDTH, TFT_HEIGHT); // Invoke custom library -TFT_eSPI tft = TFT_eSPI(240, 240); // Invoke custom library +// Extra char (+1) for null +#define LINE_BUFFER_SIZE 20 // How often we are redrawing screen #define USER_LOOP_REFRESH_RATE_MS 1000 +extern int getSignalQuality(int rssi); + //class name. Use something descriptive and leave the ": public Usermod" part :) class St7789DisplayUsermod : public Usermod { @@ -45,9 +66,70 @@ class St7789DisplayUsermod : public Usermod { uint8_t knownBrightness = 0; uint8_t knownMode = 0; uint8_t knownPalette = 0; - uint8_t tftcharwidth = 19; // Number of chars that fit on screen with text size set to 2 + uint8_t knownEffectSpeed = 0; + uint8_t knownEffectIntensity = 0; + uint8_t knownMinute = 99; + uint8_t knownHour = 99; + + const uint8_t tftcharwidth = 19; // Number of chars that fit on screen with text size set to 2 long lastUpdate = 0; + void center(String &line, uint8_t width) { + int len = line.length(); + if (len0; i--) line = ' ' + line; + for (byte i=line.length(); i 12) { + showHour -= 12; + isAM = false; + } else { + isAM = true; + } + } + + sprintf_P(lineBuffer, PSTR("%2d:%02d"), (useAMPM ? showHour : hourCurrent), minuteCurrent); + tft.setTextColor(TFT_WHITE); + tft.setTextSize(4); + tft.setCursor(60, 24); + tft.print(lineBuffer); + + tft.setTextSize(2); + tft.setCursor(186, 24); + //sprintf_P(lineBuffer, PSTR("%02d"), secondCurrent); + if (useAMPM) tft.print(isAM ? "AM" : "PM"); + //else tft.print(lineBuffer); + } + public: //Functions called by WLED @@ -57,6 +139,9 @@ class St7789DisplayUsermod : public Usermod { */ void setup() { + PinManagerPinType pins[] = { { TFT_MOSI, true }, { TFT_MISO, false}, { TFT_SCLK, true }, { TFT_CS, true}, { TFT_DC, true}, { TFT_RST, true }, { TFT_BL, true } }; + if (!pinManager.allocateMultiplePins(pins, 5, PinOwner::UM_FourLineDisplay)) { return; } + tft.init(); tft.setRotation(0); //Rotation here is set up for the text to be readable with the port on the left. Use 1 to flip. tft.fillScreen(TFT_BLACK); @@ -65,10 +150,10 @@ class St7789DisplayUsermod : public Usermod { tft.setTextDatum(MC_DATUM); tft.setTextSize(2); tft.print("Loading..."); - if (TFT_BL > 0) - { // TFT_BL has been set in the TFT_eSPI library - pinMode(TFT_BL, OUTPUT); // Set backlight pin to output mode - digitalWrite(TFT_BL, HIGH); // Turn backlight on. + if (TFT_BL >= 0) + { + pinMode(TFT_BL, OUTPUT); // Set backlight pin to output mode + digitalWrite(TFT_BL, HIGH); // Turn backlight on. } } @@ -91,174 +176,189 @@ class St7789DisplayUsermod : public Usermod { * Instead, use a timer check as shown here. */ void loop() { -// Check if we time interval for redrawing passes. - if (millis() - lastUpdate < USER_LOOP_REFRESH_RATE_MS) + char buff[LINE_BUFFER_SIZE]; + + // Check if we time interval for redrawing passes. + if (millis() - lastUpdate < USER_LOOP_REFRESH_RATE_MS) { return; } - lastUpdate = millis(); + lastUpdate = millis(); -// Turn off display after 5 minutes with no change. - if(!displayTurnedOff && millis() - lastRedraw > 5*60*1000) + // Turn off display after 5 minutes with no change. + if (!displayTurnedOff && millis() - lastRedraw > 5*60*1000) { - digitalWrite(TFT_BL, LOW); // Turn backlight off. + if (TFT_BL >= 0) digitalWrite(TFT_BL, LOW); // Turn backlight off. displayTurnedOff = true; } -// Check if values which are shown on display changed from the last time. - if (((apActive) ? String(apSSID) : WiFi.SSID()) != knownSsid) - { - needRedraw = true; - } - else if (knownIp != (apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP())) - { - needRedraw = true; - } - else if (knownBrightness != bri) - { - needRedraw = true; - } - else if (knownMode != strip.getMode()) - { - needRedraw = true; - } - else if (knownPalette != strip.getSegment(0).palette) - { - needRedraw = true; - } - - if (!needRedraw) - { - return; - } - needRedraw = false; - - if (displayTurnedOff) - { - digitalWrite(TFT_BL, TFT_BACKLIGHT_ON); // Turn backlight on. - displayTurnedOff = false; - } - lastRedraw = millis(); - -// Update last known values. - #if defined(ESP8266) - knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID(); - #else - knownSsid = WiFi.SSID(); - #endif - knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP(); - knownBrightness = bri; - knownMode = strip.getMode(); - knownPalette = strip.getSegment(0).palette; - - tft.fillScreen(TFT_BLACK); - tft.setTextSize(2); -// First row with Wifi name - tft.setTextColor(TFT_SILVER); - tft.setCursor(3, 40); - tft.print(knownSsid.substring(0, tftcharwidth > 1 ? tftcharwidth - 1 : 0)); -// Print `~` char to indicate that SSID is longer, than our dicplay - if (knownSsid.length() > tftcharwidth) - tft.print("~"); - -// Second row with AP IP and Password or IP - tft.setTextColor(TFT_GREEN); - tft.setTextSize(2); - tft.setCursor(3, 64); -// Print AP IP and password in AP mode or knownIP if AP not active. - - if (apActive) - { - tft.setTextColor(TFT_YELLOW); - tft.print("AP IP: "); - tft.print(knownIp); - tft.setCursor(3,86); - tft.setTextColor(TFT_YELLOW); - tft.print("AP Pass:"); - tft.print(apPass); - } - else - { - tft.setTextColor(TFT_GREEN); - tft.print("IP: "); - tft.print(knownIp); - tft.setCursor(3,86); - //tft.print("Signal Strength: "); - //tft.print(i.wifi.signal); - tft.setTextColor(TFT_WHITE); - tft.print("Bri: "); - tft.print(((float(bri)/255)*100),0); - tft.print("%"); - } - -// Third row with mode name - tft.setCursor(3, 108); - uint8_t qComma = 0; - bool insideQuotes = false; - uint8_t printedChars = 0; - char singleJsonSymbol; -// Find the mode name in JSON - for (size_t i = 0; i < strlen_P(JSON_mode_names); i++) - { - singleJsonSymbol = pgm_read_byte_near(JSON_mode_names + i); - switch (singleJsonSymbol) + // Check if values which are shown on display changed from the last time. + if ((((apActive) ? String(apSSID) : WiFi.SSID()) != knownSsid) || + (knownIp != (apActive ? IPAddress(4, 3, 2, 1) : Network.localIP())) || + (knownBrightness != bri) || + (knownEffectSpeed != effectSpeed) || + (knownEffectIntensity != effectIntensity) || + (knownMode != strip.getMode()) || + (knownPalette != strip.getSegment(0).palette)) { + needRedraw = true; + } + + if (!needRedraw) + { + return; + } + needRedraw = false; + + if (displayTurnedOff) + { + digitalWrite(TFT_BL, HIGH); // Turn backlight on. + displayTurnedOff = false; + } + lastRedraw = millis(); + + // Update last known values. + #if defined(ESP8266) + knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID(); + #else + knownSsid = WiFi.SSID(); + #endif + knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP(); + knownBrightness = bri; + knownMode = strip.getMode(); + knownPalette = strip.getSegment(0).palette; + knownEffectSpeed = effectSpeed; + knownEffectIntensity = effectIntensity; + + tft.fillScreen(TFT_BLACK); + + showTime(); + + tft.setTextSize(2); + + // Wifi name + tft.setTextColor(TFT_GREEN); + tft.setCursor(0, 60); + String line = knownSsid.substring(0, tftcharwidth-1); + // Print `~` char to indicate that SSID is longer, than our display + if (knownSsid.length() > tftcharwidth) line = line.substring(0, tftcharwidth-1) + '~'; + center(line, tftcharwidth); + tft.print(line.c_str()); + + // Print AP IP and password in AP mode or knownIP if AP not active. + if (apActive) + { + tft.setCursor(0, 84); + tft.print("AP IP: "); + tft.print(knownIp); + tft.setCursor(0,108); + tft.print("AP Pass:"); + tft.print(apPass); + } + else + { + tft.setCursor(0, 84); + line = knownIp.toString(); + center(line, tftcharwidth); + tft.print(line.c_str()); + // percent brightness + tft.setCursor(0, 120); + tft.setTextColor(TFT_WHITE); + tft.print("Bri: "); + tft.print((((int)bri*100)/255)); + tft.print("%"); + // signal quality + tft.setCursor(124,120); + tft.print("Sig: "); + if (getSignalQuality(WiFi.RSSI()) < 10) { + tft.setTextColor(TFT_RED); + } else if (getSignalQuality(WiFi.RSSI()) < 25) { + tft.setTextColor(TFT_ORANGE); + } else { + tft.setTextColor(TFT_GREEN); + } + tft.print(getSignalQuality(WiFi.RSSI())); + tft.setTextColor(TFT_WHITE); + tft.print("%"); + } + + // mode name + tft.setTextColor(TFT_CYAN); + tft.setCursor(0, 144); + uint8_t qComma = 0; + bool insideQuotes = false; + uint8_t printedChars = 0; + char singleJsonSymbol; + // Find the mode name in JSON + for (size_t i = 0; i < strlen_P(JSON_mode_names); i++) + { + singleJsonSymbol = pgm_read_byte_near(JSON_mode_names + i); + switch (singleJsonSymbol) + { + case '"': + insideQuotes = !insideQuotes; + break; + case '[': + case ']': + break; + case ',': + qComma++; + default: + if (!insideQuotes || (qComma != knownMode)) + break; + tft.print(singleJsonSymbol); + printedChars++; + } + if ((qComma > knownMode) || (printedChars > tftcharwidth - 1)) + break; + } + + // palette name + tft.setTextColor(TFT_YELLOW); + tft.setCursor(0, 168); + qComma = 0; + insideQuotes = false; + printedChars = 0; + // Looking for palette name in JSON. + for (size_t i = 0; i < strlen_P(JSON_palette_names); i++) + { + singleJsonSymbol = pgm_read_byte_near(JSON_palette_names + i); + switch (singleJsonSymbol) + { case '"': insideQuotes = !insideQuotes; - break; - case '[': - case ']': - break; - case ',': - qComma++; - default: - if (!insideQuotes || (qComma != knownMode)) break; - tft.setTextColor(TFT_MAGENTA); - tft.print(singleJsonSymbol); - printedChars++; - } - if ((qComma > knownMode) || (printedChars > tftcharwidth - 1)) - break; - } -// Fourth row with palette name - tft.setTextColor(TFT_YELLOW); - tft.setCursor(3, 130); - qComma = 0; - insideQuotes = false; - printedChars = 0; -// Looking for palette name in JSON. - for (size_t i = 0; i < strlen_P(JSON_palette_names); i++) - { - singleJsonSymbol = pgm_read_byte_near(JSON_palette_names + i); - switch (singleJsonSymbol) - { - case '"': - insideQuotes = !insideQuotes; - break; - case '[': - case ']': - break; - case ',': - qComma++; - default: - if (!insideQuotes || (qComma != knownPalette)) + case '[': + case ']': break; - tft.print(singleJsonSymbol); - printedChars++; + case ',': + qComma++; + default: + if (!insideQuotes || (qComma != knownPalette)) + break; + tft.print(singleJsonSymbol); + printedChars++; + } + // The following is modified from the code from the u8g2/u8g8 based code (knownPalette was knownMode) + if ((qComma > knownPalette) || (printedChars > tftcharwidth - 1)) + break; } -// The following is modified from the code from the u8g2/u8g8 based code (knownPalette was knownMode) - if ((qComma > knownPalette) || (printedChars > tftcharwidth - 1)) - break; - } -// Fifth row with estimated mA usage - tft.setTextColor(TFT_SILVER); - tft.setCursor(3, 152); -// Print estimated milliamp usage (must specify the LED type in LED prefs for this to be a reasonable estimate). - tft.print("Current: "); - tft.print(strip.currentMilliamps); - tft.print("mA"); + + tft.setCursor(0, 192); + tft.setTextColor(TFT_SILVER); + sprintf_P(buff, PSTR("FX Spd:%3d Int:%3d"), effectSpeed, effectIntensity); + tft.print(buff); + + // Fifth row with estimated mA usage + tft.setTextColor(TFT_SILVER); + tft.setCursor(0, 216); + // Print estimated milliamp usage (must specify the LED type in LED prefs for this to be a reasonable estimate). + tft.print("Current: "); + tft.setTextColor(TFT_ORANGE); + tft.print(strip.currentMilliamps); + tft.print("mA"); } + /* * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API. * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI. @@ -295,7 +395,7 @@ class St7789DisplayUsermod : public Usermod { */ void readFromJsonState(JsonObject& root) { - userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value + //userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value //if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!")); } @@ -316,8 +416,8 @@ class St7789DisplayUsermod : public Usermod { */ void addToConfig(JsonObject& root) { - JsonObject top = root.createNestedObject("exampleUsermod"); - top["great"] = userVar0; //save this var persistently whenever settings are saved + //JsonObject top = root.createNestedObject("exampleUsermod"); + //top["great"] = userVar0; //save this var persistently whenever settings are saved } @@ -329,10 +429,11 @@ class St7789DisplayUsermod : public Usermod { * but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup. * If you don't know what that is, don't fret. It most likely doesn't affect your use case :) */ - void readFromConfig(JsonObject& root) + bool readFromConfig(JsonObject& root) { - JsonObject top = root["top"]; - userVar0 = top["great"] | 42; //The value right of the pipe "|" is the default value in case your setting was not present in cfg.json (e.g. first boot) + //JsonObject top = root["top"]; + //userVar0 = top["great"] | 42; //The value right of the pipe "|" is the default value in case your setting was not present in cfg.json (e.g. first boot) + return true; } @@ -342,7 +443,7 @@ class St7789DisplayUsermod : public Usermod { */ uint16_t getId() { - return USERMOD_ST7789_DISPLAY; + return USERMOD_ID_ST7789_DISPLAY; } //More methods can be added in the future, this example will then be extended. diff --git a/usermods/ST7789_display/Setup_ST7789_Display.h b/usermods/ST7789_display/Setup_ST7789_Display.h deleted file mode 100644 index 26d5c17ff..000000000 --- a/usermods/ST7789_display/Setup_ST7789_Display.h +++ /dev/null @@ -1,39 +0,0 @@ -// Setup for the ESP32 board with 1.5" 240x240 display - -// See SetupX_Template.h for all options available - -#define ST7789_DRIVER -#define TFT_SDA_READ // Display has a bidirectionsl SDA pin - -#define TFT_WIDTH 240 -#define TFT_HEIGHT 240 - -#define CGRAM_OFFSET // Library will add offsets required - -//#define TFT_MISO -1 - -#define TFT_MOSI 21 -#define TFT_SCLK 22 -//#define TFT_CS 5 -#define TFT_DC 18 -#define TFT_RST 5 - -#define TFT_BL 26 // Display backlight control pin - -#define TFT_BACKLIGHT_ON HIGH // HIGH or LOW are options - -#define LOAD_GLCD -#define LOAD_FONT2 -#define LOAD_FONT4 -#define LOAD_FONT6 -#define LOAD_FONT7 -#define LOAD_FONT8 -#define LOAD_GFXFF - -//#define SMOOTH_FONT - -//#define SPI_FREQUENCY 27000000 - #define SPI_FREQUENCY 40000000 // Maximum for ILI9341 - - -#define SPI_READ_FREQUENCY 6000000 // 6 MHz is the maximum SPI read speed for the ST7789V \ No newline at end of file diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp index fd5ffffdb..4684e53fa 100644 --- a/wled00/usermods_list.cpp +++ b/wled00/usermods_list.cpp @@ -86,6 +86,10 @@ #include "../usermods/rgb-rotary-encoder/rgb-rotary-encoder.h" #endif +#ifdef USERMOD_ST7789_DISPLAY +#include "../usermods/ST7789_display/ST7789_Display.h" +#endif + void registerUsermods() { /* @@ -167,4 +171,8 @@ void registerUsermods() #ifdef RGB_ROTARY_ENCODER usermods.add(new RgbRotaryEncoderUsermod()); #endif + + #ifdef USERMOD_ST7789_DISPLAY + usermods.add(new St7789DisplayUsermod()); + #endif } diff --git a/wled00/wled.h b/wled00/wled.h index c127c4d51..9694be7dc 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2108271 +#define VERSION 2108281 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG