diff --git a/platformio.ini b/platformio.ini index 7b50f693..5002cc89 100644 --- a/platformio.ini +++ b/platformio.ini @@ -417,11 +417,21 @@ lib_ignore = [env:wemos_shield_esp32] board = esp32dev platform = espressif32@3.2 -upload_port = /dev/cu.SLAB_USBtoUART -monitor_port = /dev/cu.SLAB_USBtoUART upload_speed = 460800 build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags_esp32} -D LEDPIN=16 -D RLYPIN=19 -D BTNPIN=17 +build_flags = ${common.build_flags_esp32} + -D LEDPIN=16 + -D RLYPIN=19 + -D BTNPIN=17 + -D UWLED_USE_MY_CONFIG +; -D USERMOD_DALLASTEMPERATURE +; -D USERMOD_DALLASTEMPERATURE_CELCIUS +; -D USERMOD_FOUR_LINE_DISPLAY +; -D TEMPERATURE_PIN=21 +lib_deps = ${env.lib_deps} +; OneWire@~2.3.5 +; milesburton/DallasTemperature@^3.9.0 +; U8g2@~2.27.2 lib_ignore = ESPAsyncTCP ESPAsyncUDP @@ -511,3 +521,4 @@ monitor_filters = esp32_exception_decoder lib_ignore = ESPAsyncTCP ESPAsyncUDP + \ No newline at end of file diff --git a/readme.md b/readme.md index 9cee21f3..c3f5987e 100644 --- a/readme.md +++ b/readme.md @@ -9,7 +9,6 @@

- # Welcome to my project WLED! ✨ A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B, WS2811, SK6812) LEDs or also SPI based chipsets like the WS2801 and APA102! diff --git a/usermods/ST7789_display/README.md b/usermods/ST7789_display/README.md new file mode 100644 index 00000000..653fdd75 --- /dev/null +++ b/usermods/ST7789_display/README.md @@ -0,0 +1,72 @@ +# ST7789 TFT IPS Color display 240x240pxwith ESP32 boards + +This usermod allow to use 240x240 display to display following: + +* Network SSID; +* IP address; +* Brightness; +* Chosen effect; +* Chosen palette; +* Estimated current in mA; + +## Hardware + +*** +![Hardware](images/ST7789_guide.jpg) + +## Library used + +[Bodmer/TFT_eSPI](https://github.com/Bodmer/TFT_eSPI) + +## Setup + +*** + +### Platformio.ini changes + +In the `platformio.ini` file, uncomment the `TFT_eSPI` line within the [common] section, under `lib_deps`: + +```ini +# platformio.ini +... +[common] +... +lib_deps = + ... + #For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line + #TFT_eSPI +... +``` + +Also, while in the `platformio.ini` file, you must change the environment setup to build for just the esp32dev platform as follows: + +Add lines to section: + +```ini +default_envs = esp32dev +build_flags = ${common.build_flags_esp32} + -D USERMOD_ST7789_DISPLAY + +``` + +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. + +Modify the `User_Setup_Select.h` file as follows: + +* Comment out the following line (which is the 'default' setup file): + +```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` diff --git a/usermods/ST7789_display/ST7789_display.h b/usermods/ST7789_display/ST7789_display.h new file mode 100644 index 00000000..bd501d08 --- /dev/null +++ b/usermods/ST7789_display/ST7789_display.h @@ -0,0 +1,350 @@ +// Credits to @mrVanboy, @gwaland and my dearest friend @westward +// Also for @spiff72 for usermod TTGO-T-Display +// 210217 +#pragma once + +#include "wled.h" +#include +#include + +#define USERMOD_ST7789_DISPLAY 97 + +#ifndef TFT_DISPOFF +#define TFT_DISPOFF 0x28 +#endif + +#ifndef TFT_SLPIN +#define TFT_SLPIN 0x10 +#endif + +#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(240, 240); // Invoke custom library + +// How often we are redrawing screen +#define USER_LOOP_REFRESH_RATE_MS 1000 + + +//class name. Use something descriptive and leave the ": public Usermod" part :) +class St7789DisplayUsermod : public Usermod { + private: + //Private class members. You can declare variables and functions only accessible to your usermod here + unsigned long lastTime = 0; + + bool displayTurnedOff = false; + long lastRedraw = 0; + // needRedraw marks if redraw is required to prevent often redrawing. + bool needRedraw = true; + // Next variables hold the previous known values to determine if redraw is required. + String knownSsid = ""; + IPAddress knownIp; + 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 + long lastUpdate = 0; + + public: + //Functions called by WLED + + /* + * setup() is called once at boot. WiFi is not yet connected at this point. + * You can use it to initialize variables, sensors or similar. + */ + void setup() + { + 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); + tft.setTextColor(TFT_RED); + tft.setCursor(60, 100); + 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. + } + } + + /* + * connected() is called every time the WiFi is (re)connected + * Use it to initialize network interfaces + */ + void connected() { + //Serial.println("Connected to WiFi!"); + } + + /* + * loop() is called continuously. Here you can check for events, read sensors, etc. + * + * Tips: + * 1. You can use "if (WLED_CONNECTED)" to check for a successful network connection. + * Additionally, "if (WLED_MQTT_CONNECTED)" is available to check for a connection to an MQTT broker. + * + * 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds. + * 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) + { + return; + } + lastUpdate = millis(); + +// Turn off display after 5 minutes with no change. + if(!displayTurnedOff && millis() - lastRedraw > 5*60*1000) + { + 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) + { + 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)) + 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; + } +// 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"); + } + /* + * 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. + * Below it is shown how this could be used for e.g. a light sensor + */ + /* + void addToJsonInfo(JsonObject& root) + { + int reading = 20; + //this code adds "u":{"Light":[20," lux"]} to the info object + JsonObject user = root["u"]; + if (user.isNull()) user = root.createNestedObject("u"); + + JsonArray lightArr = user.createNestedArray("Light"); //name + lightArr.add(reading); //value + lightArr.add(" lux"); //unit + } + */ + + + /* + * addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object). + * Values in the state object may be modified by connected clients + */ + void addToJsonState(JsonObject& root) + { + //root["user0"] = userVar0; + } + + + /* + * readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object). + * Values in the state object may be modified by connected clients + */ + void readFromJsonState(JsonObject& root) + { + 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!")); + } + + + /* + * addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object. + * It will be called by WLED when settings are actually saved (for example, LED settings are saved) + * If you want to force saving the current state, use serializeConfig() in your loop(). + * + * CAUTION: serializeConfig() will initiate a filesystem write operation. + * It might cause the LEDs to stutter and will cause flash wear if called too often. + * Use it sparingly and always in the loop, never in network callbacks! + * + * addToConfig() will also not yet add your setting to one of the settings pages automatically. + * To make that work you still have to add the setting to the HTML, xml.cpp and set.cpp manually. + * + * I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings! + */ + void addToConfig(JsonObject& root) + { + JsonObject top = root.createNestedObject("exampleUsermod"); + top["great"] = userVar0; //save this var persistently whenever settings are saved + } + + + /* + * readFromConfig() can be used to read back the custom settings you added with addToConfig(). + * This is called by WLED when settings are loaded (currently this only happens once immediately after boot) + * + * readFromConfig() is called BEFORE setup(). This means you can use your persistent values in setup() (e.g. pin assignments, buffer sizes), + * 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) + { + 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) + } + + + /* + * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). + * This could be used in the future for the system to determine whether your usermod is installed. + */ + uint16_t getId() + { + return USERMOD_ST7789_DISPLAY; + } + + //More methods can be added in the future, this example will then be extended. + //Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class! +}; \ No newline at end of file diff --git a/usermods/ST7789_display/Setup_ST7789_Display.h b/usermods/ST7789_display/Setup_ST7789_Display.h new file mode 100644 index 00000000..26d5c17f --- /dev/null +++ b/usermods/ST7789_display/Setup_ST7789_Display.h @@ -0,0 +1,39 @@ +// 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/usermods/ST7789_display/images/ST7789_Guide.jpg b/usermods/ST7789_display/images/ST7789_Guide.jpg new file mode 100644 index 00000000..80fee420 Binary files /dev/null and b/usermods/ST7789_display/images/ST7789_Guide.jpg differ