autoconfig.corz.org uses cookies to remember that you've seen this notice explaining that autoconfig.corz.org uses cookies, okay!
autoconfig.corz.org text viewer..
[currently viewing: / public/ scripts/ ESP32/ CYD_Slideshow/ CYD_SlideShow.ino - raw]
String version = "1.0.38c";
Preferences prefs;
void START_PREFS() {}
uint16_t delayTime = 15;
uint16_t maxTime = 60;
uint16_t txtColor = 0x3D25;
uint16_t msgColor = txtColor;
uint16_t bgColor = TFT_BLACK;
uint16_t fnColor = 0x3A87;
const uint8_t backlightPin = 21;
bool allowRandomImages = true;
bool showRandomImage = false;
bool sensorControlsBackLight = true;
const uint8_t lightSensorPin = 34;
uint16_t LDRLo = 250;
uint16_t LDRHi = 1400;
uint8_t debugLevel = 3;
void END_PREFS() {}
BB_SPI_LCD lcd;
JPEGDisplay jpeg;
SPIClass SD_SPI;
File file, root, previousFile;
const char *compile_time = __TIMESTAMP__;
int16_t maxBrightness = 255;
uint16_t iWidth, iHeight;
uint64_t currentTime;
uint64_t lastTouchTime = millis();
uint64_t lastImageTime = 0;
bool slideShowPaused = false;
bool isPrevious = false;
uint64_t lastSensorCheck = 0;
int16_t currentBrightness = maxBrightness;
uint8_t clearLength;
uint64_t SSPausedAt;
uint16_t fileCount = 0;
bool msgAtTop = true;
bool showFileNames = false;
bool namesAtTop = false;
uint16_t currentID;
uint16_t RtxtColor = txtColor;
uint16_t RmsgColor = msgColor;
uint16_t RbgColor = bgColor;
uint16_t RfnColor = fnColor;
uint16_t seenImageIDs[MAX_ITEMS] = {0};
uint8_t seenBitmap[BITSET_SIZE] = {0};
int16_t seenB4 = 0;
int16_t listCount = 0;
bool pressInProgress = false;
bool longPressHandled = false;
uint32_t pressStartedAt = 0;
float progress;
uint16_t indicatorRadius = 64;
uint8_t indicatorThickness = 12;
const char strRandom[] PROGMEM = "Random";
const char strSequential[] PROGMEM = "Sequential";
void doInfoMessage(String msg, uint16_t myColor = msgColor, bool top = msgAtTop, uint8_t myDebugLevel = 0) {
if (msg.length() > clearLength) clearLength = msg.length() + 2;
uint16_t myY = 4;
if (!top) myY = iHeight - 16;
lcd.fillRect(iWidth/2 - ((clearLength/2) * 8), myY, (clearLength * 8), 12, bgColor, DRAW_TO_LCD);
clearLength = msg.length() + 2;
lcd.setCursor(iWidth/2 - ((msg.length()/2) * 8), myY);
lcd.setTextColor(myColor, bgColor);
lcd.println(msg.c_str());
lcd.setTextColor(txtColor, bgColor);
if (debugLevel > myDebugLevel) Serial.println(" " + msg);
}
void doReport(String myMessage, uint8_t myDebugLevel = 0) {
lcd.println(myMessage.c_str());
if (debugLevel > myDebugLevel) Serial.print(myMessage.c_str());
}
void mountSD(bool firstNotify) {
SD_SPI.begin(SD_SCK, SD_MISO, SD_MOSI, SD_CS);
if (!SD.begin(SD_CS, SD_SPI, 10000000)) {
if (firstNotify) {
doReport(" Card Mount FAILED.\n");
}
if(SD.cardType() == CARD_NONE) {
if (firstNotify) {
doReport("\n Please insert an SD card.\n");
}
delay(3000);
mountSD(false);
}
} else {
doReport(" SD Card Mounted.\n");
SD.rmdir("System Volume Information");
}
}
void rebootESP() {
Serial.flush();
ESP.restart();
}
void quickFileCount() {
File disk = SD.open("/");
if (!disk || !disk.isDirectory()) {
doReport(" Problem with root directory. Check your SD Card.\n");
}
doReport("\n Scanning files..\n", 1);
String lookFile = disk.getNextFileName();
if (debugLevel == 6) Serial.printf(" [1]: %s\n", lookFile.c_str());
if (lookFile == "") {
doReport(" Empty Card\n");
return;
}
uint64_t currentTime = millis();
while (lookFile != "" && fileCount <= MAX_ITEMS) {
lookFile = disk.getNextFileName();
fileCount++;
if (lookFile != "" && debugLevel == 6) Serial.printf(" [%i]: %s\n", fileCount+1, lookFile.c_str());
}
if (debugLevel > 1) doReport(" Scan complete in " + (String)((float_t)(millis() - currentTime) / 1000) + "s.\n\n");
if (debugLevel > 1 && fileCount > 0) {
doReport(" Total Files: " + (String)fileCount + "\n");
doReport(" Average Size: " + (String)((float)(SD.usedBytes() / fileCount) / 1024) + "KiB\n");
}
}
bool hasJPEGExtension(String fileName) {
if (debugLevel > 2) Serial.printf(" checking extension of '%s'\n", fileName.c_str());
String myExt = fileName.substring(fileName.lastIndexOf('.')+1);
myExt.toLowerCase();
return (!myExt.compareTo("jpg") || !myExt.compareTo("jpeg"));
}
void showImage(String nowImage) {
String fullPath = "/" + nowImage;
if (debugLevel == 13) fullPath += "fooMeBaby";
if (debugLevel > 1) Serial.printf(" Loading image: %s\n", nowImage.c_str());
lcd.fillScreen(bgColor);
jpeg.loadJPEG(&lcd, JPEGDISPLAY_CENTER, JPEGDISPLAY_CENTER, fullPath.c_str());
if (showFileNames) doInfoMessage(nowImage, fnColor, namesAtTop, 2);
seenB4 = 0;
}
void next() {
file = root.openNextFile();
}
void displayImage(uint64_t nowTime = lastImageTime) {
lastImageTime = nowTime;
isPrevious = false;
while (true) {
if (!file) {
root.rewindDirectory();
next();
}
if (!file) {
if (debugLevel) Serial.println(F("\n\n SD Removed!\n Rebooting..\n\n"));
rebootESP();
}
if (file.isDirectory()) {
next();
continue;
}
if (hasJPEGExtension(file.name())) {
showImage(file.name());
break;
} else {
next();
}
}
}
bool seenID(uint16_t imgID) {
return seenBitmap[imgID / 8] & (1 << (imgID % 8));
}
bool storeID(uint16_t imgID) {
if (debugLevel > 2) Serial.printf(" Storing ID: %i\n", imgID);
if (seenID(imgID)) return false;
seenBitmap[imgID / 8] |= (1 << (imgID % 8));
seenImageIDs[listCount++] = imgID;
if (debugLevel == 5) printFileIDsReversed();
return true;
}
void resetList() {
if (debugLevel > 1) Serial.println(F(" Resetting 'seen' images list.\n"));
listCount = 0;
memset(seenBitmap, 0, sizeof(seenBitmap));
memset(seenImageIDs, 0, sizeof(seenImageIDs));
}
void printFileIDsReversed() {
Serial.printf(" File ID's: ");
for (int i = listCount-1; i >= 0; i--) {
Serial.printf("%i", seenImageIDs[i]);
Serial.print((i > 0) ? ", " : ".");
}
Serial.println("");
}
bool removeLastID() {
if (listCount == 0) return false;
uint16_t lastID = seenImageIDs[listCount - 1];
seenBitmap[lastID / 8] &= ~(1 << (lastID % 8));
seenImageIDs[--listCount] = 0;
return true;
}
void selectImage(uint64_t nowTime, uint16_t myID = 0) {
if (debugLevel > 1) Serial.printf("\n Searching for image.. [%s]\n", (myID != 0) ? String(myID).c_str() : "random");
uint16_t count = 0;
bool manualSet = false;
String tFile;
uint16_t fileID;
if (myID != 0) {
if (myID > fileCount) myID = fileCount;
fileID = myID;
manualSet = true;
} else {
fileID = random(1, fileCount-1);
}
if (!manualSet && !storeID(fileID)) {
if (debugLevel > 1) Serial.println(F(" Seen this image already! Trying again.."));
seenB4++;
if (seenB4 > 4) {
if (debugLevel > 1) Serial.println(F(" Encountered five consecutive ID clashes."));
resetList();
}
selectImage(nowTime);
return;
}
root.rewindDirectory();
for (uint16_t filez = 1; filez < fileID; filez++ ) {
tFile = root.getNextFileName();
if (tFile == "") rebootESP();
count++;
}
next();
count++;
currentID = count;
if (file) {
if (debugLevel > 2) Serial.printf(" Using file %u: %s\n", count, file.name());
} else {
if (debugLevel > 1) Serial.printf(" Failed to open file %u:\n", count);
}
}
void showNextImage(uint64_t nowTime) {
if (file) previousFile = file;
if (showRandomImage) {
selectImage(nowTime);
} else {
next();
}
displayImage(nowTime);
}
void previousImage(uint64_t nowTime = lastImageTime) {
lastImageTime = nowTime;
isPrevious = true;
if (debugLevel > 1 && previousFile) Serial.printf(" Showing Previous Image: %s\n", previousFile.name());
if (previousFile) showImage(previousFile.name());
}
void reLoad() {
if (isPrevious) {
previousImage();
} else {
displayImage();
}
}
void setBrightness(uint8_t brightnessLevel) {
analogWrite(backlightPin, brightnessLevel);
}
void brightnessSET() {
if (debugLevel > 1) Serial.printf("\n Setting Brightness to: %lu%%\n", map(maxBrightness, 1, 255, 1, 100));
setBrightness(maxBrightness);
prefs.putShort("brightness", maxBrightness);
}
void brightnessUP(uint8_t up) {
maxBrightness += up;
if (maxBrightness > 255) maxBrightness = 255;
brightnessSET();
}
void brightnessDOWN(uint8_t down) {
maxBrightness -= down;
if (maxBrightness < 1) maxBrightness = 1;
brightnessSET();
}
void autoAdjustBackLight() {
int16_t sensorDATUM = analogRead(lightSensorPin);
if (debugLevel == 4) Serial.printf("\n sensorDATUM: %i\n", sensorDATUM);
int16_t brightness = map(sensorDATUM, LDRLo, LDRHi, maxBrightness, 5);
if (debugLevel == 4) Serial.printf(" Mapped Brightness: %i\n", brightness);
brightness = constrain(brightness, 5, maxBrightness);
if (debugLevel == 4) Serial.printf(" Constraining Brightness: %i\n", brightness);
setBrightness(brightness);
}
void delayChanged( bool doMSG = true) {
delayTime = constrain(delayTime, 1, maxTime);
prefs.putUShort("dTime", delayTime);
if (doMSG) doInfoMessage("Delay: " + (String)delayTime + "s");
if (debugLevel > 1) Serial.printf(" Delay Time changed to: %is.\n", delayTime);
}
void WipeNVRAM() {
if (debugLevel) Serial.println(F("\n Wiping NVS\n"));
esp_err_t ret = nvs_flash_init();
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
ESP_ERROR_CHECK(ret);
}
void pausePlaySlideshow(bool forcePause = false) {
if (forcePause) {
slideShowPaused = true;
} else {
slideShowPaused = !slideShowPaused;
}
if (slideShowPaused) {
if (!forcePause) doInfoMessage(F("PAUSE"));
SSPausedAt = millis();
} else {
doInfoMessage(F("PLAY"));
lastImageTime += millis() - SSPausedAt;
}
if (debugLevel > 1) Serial.printf(" Slideshow %s \n", (slideShowPaused) ? "PAUSED" : "PLAYING");
}
void toggleRandomImages() {
if (allowRandomImages) {
showRandomImage = !showRandomImage;
prefs.putBool("random", showRandomImage);
doInfoMessage(showRandomImage ? strRandom : strSequential);
} else {
doInfoMessage(F("Random Feature DISABLED"));
}
if (debugLevel) {
char buffer[12];
strcpy_P(buffer, showRandomImage ? strRandom : strSequential);
Serial.printf(" Setting image order to %s.\n", buffer);
}
}
void toggleFileNames() {
showFileNames = !showFileNames;
prefs.putBool("showNames", showFileNames);
(showFileNames) ? doInfoMessage(F("File names enabled")) : doInfoMessage(F("File names disabled"));
delay(250);
}
void printUptime() {
uint32_t seconds = millis() / 1000;
uint16_t days = seconds / 86400;
seconds %= 86400;
uint8_t hours = seconds / 3600;
seconds %= 3600;
uint8_t minutes = seconds / 60;
seconds %= 60;
Serial.printf(" Uptime: %ud %uh %um %lus\n", days, hours, minutes, seconds);
}
void printInfo() {
Serial.println(F("\n System Information: \n"));
Serial.printf(" CPU frequency: %lu MHz\n", ESP.getCpuFreqMHz());
Serial.printf(" Chip revision: %u\n", ESP.getChipRevision());
Serial.printf(" SDK version: %s\n", ESP.getSdkVersion());
auto printSize = [](const char* label, uint32_t bytes) {
if (bytes < (1024 * 1024)) {
Serial.printf(" %s: %.2f KiB\n", label, bytes / 1024.0);
} else {
Serial.printf(" %s: %.2f MiB\n", label, bytes / 1048576.0);
}
};
printSize("Flash chip size", ESP.getFlashChipSize());
printSize("Heap size", ESP.getHeapSize());
printSize("Free heap", ESP.getFreeHeap());
printSize("Min free heap", ESP.getMinFreeHeap());
printSize("Max alloc heap", ESP.getMaxAllocHeap());
Serial.print(" "); printUptime();
Serial.println(F("\n Sketch Information: \n"));
Serial.printf(" Sketch compiled: %s\n", compile_time);
Serial.printf(" Sketch MD5: %s\n", ESP.getSketchMD5().c_str());
printSize("Sketch size", ESP.getSketchSize());
printSize("Sketch free space", ESP.getFreeSketchSpace());
Serial.printf(" Used space: %.1f%%\n", (float)(100 * ESP.getSketchSize() / ESP.getFreeSketchSpace()));
Serial.println(F("\n SD Card: \n"));
printSize("SD Card Size", SD.cardSize());
printSize("Total space", SD.totalBytes());
printSize("Used space", SD.usedBytes());
if (fileCount) {
Serial.printf(" File count: %i\n", fileCount);
Serial.printf(" Average size: %.2f KiB\n", (float)(SD.usedBytes() / fileCount) / 1024);
}
Serial.println(F("\n Simple Slideshow: \n"));
Serial.printf(" Brightness: %lu%%\n", map(maxBrightness, 1, 255, 1, 100));
Serial.printf(" Image delay: %is\n", delayTime);
Serial.printf(" Image Order: %s\n", (showRandomImage) ? strRandom : strSequential);
Serial.printf(" Debug level: %i\n", debugLevel);
Serial.println();
}
const char HELP_TEXT[] PROGMEM = R"HELP(
CYD Simple Slideshow accepts the following commands:
t<*> Set Delay Time. Either an absolute value (t25 or t=25) or nudge up/down a second with t+ or t-
b<*> Set Screen Brightness. Either an absolute % value (b50 or b=100) or nudge up/down approx. 4% with b+ or b-
.|* Next Image. That's '.' or '*'. Numeric keypad operation is in mind.
0|/ Previous Image. That's '0' or '/'.
- Pause / Resume Slideshow
r Toggle Random / Sequential viewing order.
l<int> Load specific image ID.
(In random mode, IDs are printed to the serial console. Use debug level 6 for a list of all IDs at boot-up)
f Toggle show file names.
m Toggle message position (top / bottom).
n Toggle file name position (top / bottom).
sensor Toggle Sensor-controlled backlight ("ldr" also works).
tcolor=<*> Change color of boot-up text using RGB565 value, like so: tcolor=0x3D25
ncolor=<*> Change color of file names. (Note: You can also use web hex format for colors, e.g. color=
bcolor=<*> Change the background color. (Short format web hex is fine, too, e.g. color=#" is optional)
mcolor=<*> Change the message color. (All color controls use the same formats, converted internally to RGB565)
NOTES: You MUST use the '=' format to assign colors, if you want it to work.
You can send "reset" as your color value, to reset back to your hard-coded color.
d<int> Set the debug level.
z<int> TEMPORARILY set the debug level. Reverts on reboot.
reset Reset the "seen" list (in random mode).
uptime Print out ESP32 system uptime.
info Print out lots of useful information about the system and software. 'i' also works.
wipenvs Wipe NVS (permanent storage) memory. There is NO WARNING. Only use this if you want the NVS totally wiped!
help Print out this help screen. '?' also works.
reboot Reboots the ESP32 device. 'x' also works.
Single character commands with numeric values can optionally use the '=' format; d3 and d=3 both work.
"Word" commands with values *must* use the '=' format; color0x03E0 will not work.
)HELP";
void printHelp() {
Serial.println(FPSTR(HELP_TEXT));
}
uint16_t webToRGB565(const String& webColorInput, uint16_t defColor) {
String webColor = webColorInput;
if (webColor.startsWith(")) webColor.remove(0, 1);
if (webColor.length() == 3) {
// User supplied shorthand
webColor = String(webColor.charAt(0)) + webColor.charAt(0) +
webColor.charAt(1) + webColor.charAt(1) +
webColor.charAt(2) + webColor.charAt(2);
}
if (webColor.length() != 6) {
return defColor;
}
for (uint8_t i = 0; i < 6; i++) {
if (!isHexadecimalDigit(webColor.charAt(i))) {
return defColor;
}
}
uint8_t r = strtoul(webColor.substring(0, 2).c_str(), nullptr, 16);
uint8_t g = strtoul(webColor.substring(2, 4).c_str(), nullptr, 16);
uint8_t b = strtoul(webColor.substring(4, 6).c_str(), nullptr, 16);
return ((r & 0xF8) << 8) |
((g & 0xFC) << 3) |
(b >> 3);
}
String deleteImage() {
String filename;
if (isPrevious) {
filename = previousFile.name();
} else {
filename = file.name();
file.close();
}
if (filename != "") {
if (SD.remove("/" + filename)) {
return "Deleted: " + filename;
} else {
return "Failed to delete: " + filename;
}
} else {
return "Error! No file to delete!";
}
}
uint16_t getGradientColor(float progress) {
uint8_t r, g, b = 0;
if (progress <= 0.33f) {
float t = progress / 0.33f;
r = (uint8_t)(255 * t);
g = 255;
b = 0;
}
else if (progress <= 0.66f) {
float t = (progress - 0.33f) / 0.33f;
r = 255;
g = (uint8_t)(255 - 127 * t);
b = 0;
}
else {
float t = (progress - 0.66f) / 0.34f;
r = 255;
g = (uint8_t)(128 * (1.0f - t));
b = 0;
}
return lcd.color565(r, g, b);
}
void doLongPressFeedback(float progress, int16_t cx, int16_t cy, uint8_t radius = 64, uint8_t thickness = 12) {
static uint8_t lastSeg = 0;
const uint8_t segments = 45;
const uint8_t pipWidth = 3;
uint8_t endSeg = (uint8_t)(progress * segments);
if (endSeg > segments) endSeg = segments;
for (uint8_t t = 0; t < thickness; t++) {
int16_t innerRad = radius - t;
int16_t outerRad = innerRad - 1;
for (uint8_t i = lastSeg; i < endSeg; i++) {
float angle = 2.0f * PI * (float)i / segments - PI / 2;
int16_t x1 = cx + (int16_t)(innerRad * cos(angle));
int16_t y1 = cy + (int16_t)(innerRad * sin(angle));
int16_t x2 = cx + (int16_t)(outerRad * cos(angle));
int16_t y2 = cy + (int16_t)(outerRad * sin(angle));
uint16_t discColor = getGradientColor((float)i / segments);
for (int8_t dx = -pipWidth / 2; dx <= pipWidth / 2; dx++) {
for (int8_t dy = -pipWidth / 2; dy <= pipWidth / 2; dy++) {
lcd.drawLine(x1 + dx, y1 + dy, x2 + dx, y2 + dy, discColor);
}
}
}
}
lastSeg = endSeg;
}
void loop() {
currentTime = millis();
if (sensorControlsBackLight && currentTime > (lastSensorCheck + 200)) {
lastSensorCheck = currentTime;
autoAdjustBackLight();
}
bool doClear = false;
bool delayChange = false;
TOUCHINFO ti;
if (lcd.rtReadTouch(&ti) && ti.count >= 1) {
if (currentTime > (lastTouchTime + (120))) {
lastTouchTime = currentTime;
uint16_t touchX = ti.x[0];
uint16_t touchY = ti.y[0];
uint16_t touchZ = ti.pressure[0];
if (debugLevel > 2) Serial.printf(" Touch: X = %i | Y = %i | Pressure = %i\n", touchX, touchY, touchZ);
if ( (touchY >= (iHeight/4)) && (touchY <= (iHeight*3/4)) ) {
if (touchX > iWidth/4 && touchX < iWidth*3/4) {
if (!pressInProgress) {
pressInProgress = true;
longPressHandled = false;
pressStartedAt = currentTime;
}
if (!longPressHandled) {
progress = (float)(currentTime - pressStartedAt) / (float)LONG_PRESS_MS;
if (progress > 1.0) progress = 1.0;
doLongPressFeedback(progress, iWidth/2, iHeight/2, indicatorRadius, indicatorThickness);
if (progress >= 1.0) {
doInfoMessage(deleteImage());
delay(333);
longPressHandled = true;
showNextImage(currentTime);
}
}
} else if (touchX < iWidth/4) {
if (debugLevel > 2) Serial.println(F(" LEFT BUTTON: Previous image"));
previousImage(currentTime);
} else if (touchX > iWidth*3/4) {
if (debugLevel > 2) Serial.println(F(" RIGHT BUTTON: Next image"));
if (showRandomImage) doInfoMessage(F("Working.."));
showNextImage(currentTime);
}
} else {
if (touchY <= (iHeight/4)) {
if (touchX <= iWidth/9) {
brightnessUP(5);
} else if (touchX <= iWidth/6) {
brightnessUP(10);
} else if (touchX <= iWidth/3) {
brightnessUP(20);
} else if (touchX >= iWidth*2/3) {
delayTime += 1;
delayChange = true;
} else {
toggleFileNames();
doClear = true;
}
}
if (touchY >= (iHeight*3/4)) {
if (touchX <= iWidth/9) {
brightnessDOWN(5);
} else if (touchX <= iWidth/6) {
brightnessDOWN(10);
} else if (touchX <= iWidth/3) {
brightnessDOWN(20);
} else if (touchX >= iWidth*2/3) {
delayTime -= 1;
delayChange = true;
} else {
doClear = true;
toggleRandomImages();
}
}
}
if (delayChange) delayChanged();
}
} else {
if (pressInProgress) {
if (!longPressHandled) {
if (progress > 0.1) {
doInfoMessage(F("Delete cancelled"));
} else {
if (debugLevel > 2) Serial.println(F(" MIDDLE BUTTON: Play/Pause"));
pausePlaySlideshow();
}
doClear = true;
}
}
pressInProgress = false;
}
if (pressInProgress) return;
if (Serial.available() > 0) {
String rawCommand, longParams;
if (Serial.peek() > 0) rawCommand = Serial.readStringUntil('\n');
rawCommand.trim();
char cmd = rawCommand[0];
cmd = tolower(cmd);
String cmdData = rawCommand.substring(1);
cmdData.trim();
if (cmdData[0] == '=') cmdData = cmdData.substring(1);
if (cmdData.indexOf('=') != -1) {
longParams = rawCommand.substring(rawCommand.indexOf('=') + 1);
rawCommand = rawCommand.substring(0, rawCommand.indexOf('='));
}
rawCommand.toLowerCase();
if (rawCommand == "reset") {
resetList();
return;
}
if (rawCommand == "reboot" || rawCommand == "x") {
rebootESP();
}
if (rawCommand == "info" || rawCommand == "i") {
printInfo();
return;
}
if (rawCommand == "uptime") {
printUptime();
return;
}
if (rawCommand == "help" || rawCommand == "?") {
printHelp();
return;
}
if (rawCommand == "wipenvs") {
WipeNVRAM();
Serial.println(F(" NVS Wiped."));
return;
}
if (rawCommand == "sensor" || rawCommand == "ldr") {
sensorControlsBackLight = !sensorControlsBackLight;
prefs.putBool("sensor", sensorControlsBackLight);
Serial.printf(" Sensor controls backlight: %s\n", (sensorControlsBackLight) ? "ENABLED" : "DISABLED");
return;
}
if (rawCommand == "tcolor" && longParams != "") {
if (longParams.substring(0, 2) != "0x" && longParams != "reset" && longParams.charAt(0) != '
Serial.println(F("\n Incorrect color format. Use RGB565 hex value, e.g. tcolor=0x3D25\n You can also use web hex ));
} else {
if (longParams.charAt(0) == '
txtColor = webToRGB565(longParams, RtxtColor);
} else {
txtColor = (longParams == "reset") ? RtxtColor : (uint16_t)strtol(longParams.c_str(), nullptr, 0);
}
prefs.putShort("txtColor", txtColor);
Serial.printf("\n Boot-up text color %sset to: 0x%04X \n", (longParams != "reset" && txtColor != RtxtColor) ? "" : "re", txtColor);
}
return;
}
if (rawCommand == "ncolor" && longParams != "") {
if (longParams.substring(0, 2) != "0x" && longParams != "reset" && longParams.charAt(0) != '
Serial.println(F("\n Incorrect color format. Use RGB565 hex value, e.g. ncolor=0x0180\n You can also use web hex ));
} else {
if (longParams.charAt(0) == '
fnColor = webToRGB565(longParams, RfnColor);
} else {
fnColor = (longParams == "reset") ? RfnColor : (uint16_t)strtol(longParams.c_str(), nullptr, 0);
}
prefs.putShort("fnColor", fnColor);
Serial.printf("\n Filename color %sset to: 0x%04X \n", (longParams != "reset" && fnColor != RfnColor) ? "" : "re", fnColor);
}
return;
}
if (rawCommand == "mcolor" && longParams != "") {
if (longParams.substring(0, 2) != "0x" && longParams != "reset" && longParams.charAt(0) != '
Serial.println(F("\n Incorrect color format. Use RGB565 hex value, e.g. mcolor=0x3D25\n You can also use web hex ));
} else {
if (longParams.charAt(0) == '
msgColor = webToRGB565(longParams, RmsgColor);
} else {
msgColor = (longParams == "reset") ? RmsgColor : (uint16_t)strtol(longParams.c_str(), nullptr, 0);
}
prefs.putShort("msgColor", msgColor);
Serial.printf("\n Message color %sset to: 0x%04X \n", (longParams != "reset" && msgColor != RmsgColor) ? "" : "re", msgColor);
}
return;
}
if (rawCommand == "bcolor" && longParams != "") {
if (longParams.substring(0, 2) != "0x" && longParams != "reset" && longParams.charAt(0) != '
Serial.println(F("\n Incorrect color format. Use RGB565 hex value, e.g. bcolor=0x0000\n You can also use web hex ));
} else {
if (longParams.charAt(0) == '
bgColor = webToRGB565(longParams, RbgColor);
} else {
bgColor = (longParams == "reset") ? RbgColor : (uint16_t)strtol(longParams.c_str(), nullptr, 0);
}
doClear = true;
prefs.putShort("bgColor", bgColor);
Serial.printf("\n Background color %sset to: 0x%04X \n", (longParams != "reset" && bgColor != RbgColor) ? "" : "re", bgColor);
}
reLoad();
return;
}
if (cmdData == "") {
if (cmd == '.' || cmd == '*') showNextImage(currentTime);
if (cmd == '0' || cmd == '/') previousImage(currentTime);
if (cmd == 'f') {
toggleFileNames();
doClear = true;
}
if (cmd == '-') {
doClear = true;
pausePlaySlideshow();
}
if (cmd == 'r') {
doClear = true;
toggleRandomImages();
prefs.putBool("random", showRandomImage);
}
if (cmd == 'n' ) {
namesAtTop = !namesAtTop;
prefs.putBool("namesAtTop", namesAtTop);
Serial.printf(" File names at: %s\n", (namesAtTop) ? "Top" : "Bottom");
}
if (cmd == 'm') {
msgAtTop = !msgAtTop;
prefs.putBool("msgAtTop", msgAtTop);
Serial.printf(" Messages at: %s\n", (msgAtTop) ? "Top" : "Bottom");
}
}
if ((cmd == 'z' || cmd == 'd') && isDigit(cmdData[0])) {
uint8_t oldLevel = debugLevel;
debugLevel = cmdData.toInt();
Serial.printf("\n Debug level%s %s: %i\n", (cmd == 'd') ? "" : " TEMPORARILY", (debugLevel == oldLevel) ? "remains" : "set to", debugLevel);
if (cmd == 'd') {
prefs.putShort("debug", debugLevel);
if (debugLevel == 0) Serial.println(F(" NOTE: The serial connexion will be DISABLED on your next reboot.\n If you don't want this, set debug level to 1 or more.\n"));
if (debugLevel == 0) Serial.println(F(" A safer option is to use 'z0', which sets a TEMPORARY debug level of 0.\n On reboot it will revert to the previously set level.\n"));
} else {
Serial.printf(F(" Debug level will revert to previously (d)set value on reboot.\n"));
}
return;
}
if (cmd == 't' && cmdData) {
switch (cmdData[0]) {
case '+':
delayTime += 1;
break;
case '-':
delayTime -= 1;
break;
default:
delayTime = cmdData.toInt();
}
delayChanged(false);
return;
}
if (cmd == 'b' && cmdData) {
switch (cmdData[0]) {
case '+':
brightnessUP(10);
break;
case '-':
brightnessDOWN(10);
break;
default:
maxBrightness = map(constrain(cmdData.toInt(), 1, 100), 0, 100, 0, 255);
brightnessSET();
}
}
if (cmd == 'l' && cmdData) {
selectImage(currentTime, cmdData.toInt());
displayImage(currentTime);
pausePlaySlideshow(true);
}
}
if (doClear) {
delay(250);
reLoad();
return;
}
if (slideShowPaused) return;
if (lastImageTime == 0 || currentTime > (lastImageTime + (delayTime * 1000))) {
showNextImage(currentTime);
}
delay(5);
}
void setup(void) {
pinMode(lightSensorPin, INPUT);
pinMode(backlightPin, OUTPUT);
prefs.begin("CYDSS");
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) WipeNVRAM();
ESP_ERROR_CHECK(err);
debugLevel = prefs.getShort("debug", debugLevel);
if (debugLevel) Serial.begin(115200);
lcd.begin(LCD);
lcd.rtInit();
iWidth = lcd.width();
iHeight = lcd.height();
lcd.setFont(FONT_8x8);
lcd.fillScreen(bgColor);
lcd.setTextColor(txtColor, bgColor);
doReport("\n Simple Slideshow v" + version + "\n\n");
maxBrightness = prefs.getShort("brightness", maxBrightness);
delayTime = prefs.getUShort("dTime", delayTime);
showRandomImage = prefs.getBool("random", showRandomImage);
sensorControlsBackLight = prefs.getBool("sensor", sensorControlsBackLight);
showFileNames = prefs.getBool("showNames", showFileNames);
msgAtTop = prefs.getBool("msgAtTop", msgAtTop);
namesAtTop = prefs.getBool("namesAtTop", namesAtTop);
setBrightness(maxBrightness);
doReport(" Debug Level: " + (String)debugLevel + "\n\n");
doReport(" Brightness: " + (String)map(maxBrightness, 1, 255, 1, 100) + "%\n");
doReport(" Image Delay: " + (String)delayTime + "s\n");
doReport(" Image Order: " + (String)((showRandomImage) ? strRandom : strSequential) + "\n\n");
mountSD(true);
delay(250);
if (allowRandomImages) {
randomSeed(esp_random() ^ micros());
quickFileCount();
delay(1250);
} else {
showRandomImage = false;
}
Serial.print(" Playing Slideshow..\n");
root = SD.open("/");
if (!root || !root.isDirectory()) {
if (debugLevel) Serial.println(F(" Failed to open root directory. Reformat your card and try again."));
}
}