Hi all,
I have an older meeting display sign which has and does work well in every respect.
I would like to endless message scrolling. Is it possible?
Many thanks
Andy
#include <ESP8266WiFi.h>
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include <EEPROM.h>
// EEPROM addresses for WiFi credentials
#define EEPROM_SIZE 512
#define SSID_ADDR 0
#define PASS_ADDR 32
// LED matrix configuration
#define MAX_DEVICES 8
#define CLK_PIN 14 // SCK
#define DATA_PIN 13 // MOSI
#define CS_PIN 15 // SS
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// WiFi parameters
char ssid[32] = "**********";
char password[32] = "**********";
WiFiServer server(80);
// Message buffer
const uint8_t MESG_SIZE = 255;
char curMessage[MESG_SIZE];
char WebResponse[] = "HTTP/1.1 200 OK\nContent-Type: text/html\n\n";
// Message input webpage
char WebPage[] =
"<!DOCTYPE html>"
"<html>"
"<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"
"<title>ESP8266 AND MAX7219</title>"
"<style>"
"html, body { font-family: Helvetica; text-align: center; background-color: #f0f0f0; }"
"form { margin: 20px auto; width: 300px; padding: 20px; border: 1px solid #ccc; background-color: #fff; }"
"</style>"
"<script>"
"strLine = \"\";"
"function SendText() {"
" nocache = \"/&nocache=\" + Math.random() * 1000000;"
" var request = new XMLHttpRequest();"
" strLine = \"&MSG=\" + document.getElementById(\"txt_form\").Message.value;"
" request.open(\"GET\", strLine + nocache, false);"
" request.send(null);"
" alert(\"Message sent!\");"
"}"
"</script>"
"</head>"
"<body>"
"<h1>ESP8266 and MAX7219 LED Matrix</h1>"
"<form id=\"txt_form\" name=\"frmText\">"
"<label>Message: <input type=\"text\" name=\"Message\" maxlength=\"255\"></label><br><br>"
"<input type=\"submit\" value=\"Send Text\" onclick=\"SendText()\">"
"</form>"
"</body>"
"</html>";
// AP mode configuration webpage
char ConfigPage[] =
"<!DOCTYPE html>"
"<html>"
"<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"
"<title>ESP8266 WiFi Config</title>"
"<style>"
"html, body { font-family: Helvetica; text-align: center; background-color: #f0f0f0; }"
"form { margin: 20px auto; width: 300px; padding: 20px; border: 1px solid #ccc; background-color: #fff; }"
"</style>"
"</head>"
"<body>"
"<h1>Configure WiFi</h1>"
"<form method=\"GET\">"
"<label>SSID: <input type=\"text\" name=\"ssid\" maxlength=\"31\"></label><br><br>"
"<label>Password: <input type=\"text\" name=\"pass\" maxlength=\"31\"></label><br><br>"
"<input type=\"submit\" value=\"Save and Reboot\">"
"</form>"
"</body>"
"</html>";
uint8_t htoi(char c)
{
c = toupper(c);
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'A' && c <= 'F') return c - 'A' + 0xa;
return 0;
}
boolean getText(char *szMesg, char *psz, uint8_t len)
{
boolean isValid = false;
char *pStart = strstr(szMesg, "/&MSG=");
if (pStart)
{
pStart += 6;
char *pEnd = strstr(pStart, "/&");
if (pEnd)
{
while (pStart != pEnd && (psz - curMessage < len))
{
if (*pStart == '%' && isdigit(*(pStart + 1)))
{
char c = 0;
pStart++;
c += (htoi(*pStart++) << 4);
c += htoi(*pStart++);
*psz++ = c;
}
else
*psz++ = *pStart++;
}
*psz = '\0';
isValid = true;
}
}
return isValid;
}
void saveCredentials(const char* newSSID, const char* newPass)
{
for (int i = 0; i < 32; i++)
{
EEPROM.write(SSID_ADDR + i, i < strlen(newSSID) ? newSSID[i] : 0);
EEPROM.write(PASS_ADDR + i, i < strlen(newPass) ? newPass[i] : 0);
}
EEPROM.commit();
}
void loadCredentials()
{
char tempSSID[32] = "";
char tempPass[32] = "";
bool valid = true;
for (int i = 0; i < 32; i++)
{
tempSSID[i] = EEPROM.read(SSID_ADDR + i);
tempPass[i] = EEPROM.read(PASS_ADDR + i);
if (tempSSID[i] > 126 || (tempSSID[i] < 32 && tempSSID[i] != 0)) valid = false;
}
if (valid && tempSSID[0] != 0 && strlen(tempSSID) > 0)
{
strncpy(ssid, tempSSID, 32);
strncpy(password, tempPass, 32);
}
}
void handleWiFi(void)
{
static char szBuf[1024];
WiFiClient client = server.available();
if (!client || !client.connected()) return;
unsigned long timeStart = millis();
uint16_t idxBuf = 0;
while (client.available() && millis() - timeStart < 1000)
{
char c = client.read();
if (c == '\r' || c == '\n')
{
szBuf[idxBuf] = '\0';
client.flush();
if (getText(szBuf, curMessage, MESG_SIZE))
{
strcat(curMessage, " "); // Add spaces for continuous scrolling
P.displayZoneText(0, curMessage, PA_LEFT, 50, 0, PA_SCROLL_LEFT, PA_NO_EFFECT);
}
client.print(WebResponse);
client.print(WebPage);
client.stop();
return;
}
else if (idxBuf < sizeof(szBuf) - 1)
szBuf[idxBuf++] = c;
}
client.stop();
}
void handleAPMode()
{
WiFiClient client = server.available();
if (client)
{
String request = client.readStringUntil('\r');
client.flush();
if (request.indexOf("GET /?ssid=") != -1)
{
String newSSID = "";
String newPass = "";
int ssidStart = request.indexOf("ssid=") + 5;
int ssidEnd = request.indexOf("&pass=");
int passStart = request.indexOf("pass=") + 5;
int passEnd = request.indexOf(" HTTP/");
if (ssidStart != -1 && ssidEnd != -1)
newSSID = request.substring(ssidStart, ssidEnd);
if (passStart != -1 && passEnd != -1)
newPass = request.substring(passStart, passEnd);
if (newSSID.length() > 0 && newPass.length() > 0)
{
saveCredentials(newSSID.c_str(), newPass.c_str());
client.print(WebResponse);
client.print("<html><body><h1>Credentials Saved</h1><p>Rebooting...</p></body></html>");
client.stop();
delay(1000);
ESP.restart();
}
}
else
{
client.print(WebResponse);
client.print(ConfigPage);
client.stop();
}
}
}
void setup()
{
EEPROM.begin(EEPROM_SIZE);
loadCredentials();
P.begin();
P.setZone(0, 0, MAX_DEVICES - 1); // Standard zone for all modules
P.setZoneEffect(0, true, PA_FLIP_UD); // Flip up-down first
P.setZoneEffect(0, true, PA_FLIP_LR); // Then flip left-right for 180 degrees
//P.setTextAlignment(PA_CENTER);
curMessage[0] = '\0';
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
unsigned long start = millis();
while (WiFi.status() != WL_CONNECTED && millis() - start < 15000)
delay(500);
if (WiFi.status() != WL_CONNECTED)
{
WiFi.disconnect();
WiFi.mode(WIFI_AP);
WiFi.softAP("ESP8266_Config", "1234");
strcpy(curMessage, "AP Mode: ESP8266_Config");
}
else
{
sprintf(curMessage, "%03d:%03d:%03d:%03d", WiFi.localIP()[0], WiFi.localIP()[1], WiFi.localIP()[2], WiFi.localIP()[3]);
}
strcat(curMessage, ""); // Add spaces for continuous scrolling
server.begin();
P.displayZoneText(0, curMessage, PA_RIGHT, 50, 0, PA_SCROLL_RIGHT, PA_NO_EFFECT);
}
void loop()
{
if (WiFi.status() == WL_CONNECTED)
handleWiFi();
else
handleAPMode();
P.displayAnimate();
}