214 lines
6.3 KiB
C++
214 lines
6.3 KiB
C++
|
|
||
|
/*
|
||
|
* This file allows you to add own functionality to WLED more easily
|
||
|
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
||
|
* EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h)
|
||
|
* bytes 2400+ are currently ununsed, but might be used for future wled features
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Pin 2 of the TTGO T-Display serves as the data line for the LED string.
|
||
|
* Pin 35 is set up as the button pin in the platformio_overrides.ini file.
|
||
|
* The button can be set up via the macros section in the web interface.
|
||
|
* I use the button to cycle between presets.
|
||
|
* The Pin 35 button is the one on the RIGHT side of the USB-C port on the board,
|
||
|
* when the port is oriented downwards. See readme.md file for photo.
|
||
|
* The display is set up to turn off after 5 minutes, and turns on automatically
|
||
|
* when a change in the dipslayed info is detected (within a 5 second interval).
|
||
|
*/
|
||
|
|
||
|
|
||
|
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
|
||
|
|
||
|
#include "wled.h"
|
||
|
#include <TFT_eSPI.h>
|
||
|
#include <SPI.h>
|
||
|
#include "WiFi.h"
|
||
|
#include <Wire.h>
|
||
|
|
||
|
#ifndef TFT_DISPOFF
|
||
|
#define TFT_DISPOFF 0x28
|
||
|
#endif
|
||
|
|
||
|
#ifndef TFT_SLPIN
|
||
|
#define TFT_SLPIN 0x10
|
||
|
#endif
|
||
|
|
||
|
#define TFT_MOSI 19
|
||
|
#define TFT_SCLK 18
|
||
|
#define TFT_CS 5
|
||
|
#define TFT_DC 16
|
||
|
#define TFT_RST 23
|
||
|
|
||
|
#define TFT_BL 4 // Display backlight control pin
|
||
|
#define ADC_EN 14 // Used for enabling battery voltage measurements - not used in this program
|
||
|
|
||
|
TFT_eSPI tft = TFT_eSPI(135, 240); // Invoke custom library
|
||
|
|
||
|
//gets called once at boot. Do all initialization that doesn't depend on network here
|
||
|
void userSetup() {
|
||
|
Serial.begin(115200);
|
||
|
Serial.println("Start");
|
||
|
tft.init();
|
||
|
tft.setRotation(3); //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.setTextSize(2);
|
||
|
tft.setTextColor(TFT_WHITE);
|
||
|
tft.setCursor(1, 10);
|
||
|
tft.setTextDatum(MC_DATUM);
|
||
|
tft.setTextSize(2);
|
||
|
tft.print("Loading...");
|
||
|
|
||
|
if (TFT_BL > 0) { // TFT_BL has been set in the TFT_eSPI library in the User Setup file TTGO_T_Display.h
|
||
|
pinMode(TFT_BL, OUTPUT); // Set backlight pin to output mode
|
||
|
digitalWrite(TFT_BL, HIGH); // Turn backlight on.
|
||
|
}
|
||
|
|
||
|
// tft.setRotation(3);
|
||
|
}
|
||
|
|
||
|
// gets called every time WiFi is (re-)connected. Initialize own network
|
||
|
// interfaces here
|
||
|
void userConnected() {}
|
||
|
|
||
|
// 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;
|
||
|
long lastRedraw = 0;
|
||
|
bool displayTurnedOff = false;
|
||
|
// How often we are redrawing screen
|
||
|
#define USER_LOOP_REFRESH_RATE_MS 5000
|
||
|
|
||
|
void userLoop() {
|
||
|
|
||
|
// 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.setCursor(1, 10);
|
||
|
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 IP or Psssword
|
||
|
tft.setCursor(1, 40);
|
||
|
// Print password in AP mode and if led is OFF.
|
||
|
if (apActive && bri == 0)
|
||
|
tft.print(apPass);
|
||
|
else
|
||
|
tft.print(knownIp);
|
||
|
|
||
|
// Third row with mode name
|
||
|
tft.setCursor(1, 70);
|
||
|
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;
|
||
|
}
|
||
|
// Fourth row with palette name
|
||
|
tft.setCursor(1, 100);
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
}
|