diff --git a/README.md b/README.md index 3cb7702..055a23e 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,9 @@ * List of features + Edit text in real time via HomeAssistiant + Split sentences into lines (features) - + Enable/disable text scrolling (features) - + Add a drawing as a binary image (features) + + Add a drawing as a binary image + + Panel operation modes(-> Text scroll -> Image ->) || (static image + static text) + + OTA (Over The Air Updates) (features) + State of panel + Remote panel on/off # Docs for API @@ -13,3 +14,4 @@ + /api/text - endpoint for editing text (POST) + /api/led - endpint for on/off panel (POST) + /api/led - endpoint for check on/off panel (GET), return "{"led":"true"}" if panel ON and "{"led":"false"}" if panel OFF + + /api/state - endpoint for swith operation modes (POST), body: ({"State" : "1"} -> static image and static text) || body: ({"State" : "2"} -> -> Text scroll -> Image ->) diff --git a/output.h b/output.h new file mode 100644 index 0000000..beba187 --- /dev/null +++ b/output.h @@ -0,0 +1,25 @@ +#ifndef _OUTPUT_ +#define _OUTPUT_ + +byte output[16 * 32] = { +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +const int dataSize = sizeof(output) / sizeof(output[0]); + +#endif \ No newline at end of file diff --git a/panel.ino b/panel.ino index fa6f5fe..404574a 100644 --- a/panel.ino +++ b/panel.ino @@ -1,4 +1,4 @@ -//----------------include libraries----------------// +//------------------Include Libraries------------------// #include #include #include @@ -6,193 +6,219 @@ #include #include #include -//-------------------------------------------------// +#include "data/output.h" +//------------------------------------------------------// -//----------------settings panel----------------// -#define FONT Font_BOLD //Default font -#define DISPLAYS_ACROSS 1 //number of panels in width -#define DISPLAYS_DOWN 1 //number of panels in height +#define DEBUG 1 + +//------------------Settings for panel------------------// +#define FONT Font_BOLD +#define DISPLAYS_ACROSS 1 +#define DISPLAYS_DOWN 1 DMD dmd(DISPLAYS_ACROSS, DISPLAYS_DOWN); -//----------------------------------------------// +//-------------------------------------------------------// -//----------------settings local wifi----------------// -const char *ssid = "SKBKIT"; //edit for your local wifi -const char *password = "skbkit2024"; //edit for your local wifi -//---------------------------------------------------// - -//----------------settings web server----------------// -AsyncWebServer server(80); -IPAddress staticIP(10, 131, 170, 4); //edit for your local ip +//------------------Wi-Fi Settings----------------------// +const char *ssid = "SKBKIT"; +const char *password = "skbkit2024"; +IPAddress staticIP(10, 131, 170, 4); IPAddress gateway(10, 131, 170, 1); IPAddress subnet(255, 255, 255, 0); -//---------------------------------------------------// +//-------------------------------------------------------// -//----------------other variables----------------// -String displayText = "Привет из СКБ \"КИТ\""; //change the default label +//------------------Web Server Settings-----------------// +AsyncWebServer server(80); +//-------------------------------------------------------// + +//------------------Other Variables---------------------// +String displayText = "Привет из СКБ \"КИТ\""; +bool isScrolling = true; +bool showImage = false; +unsigned long lastScrollTime = 0; +unsigned long scrollDuration = 5000; +unsigned long imageStartTime = 0; hw_timer_t *timer = NULL; -bool panel = true; -//-----------------------------------------------// +//-------------------------------------------------------// -//---Search SPI panel---// -void IRAM_ATTR triggerScan() { - dmd.scanDisplayBySPI(); -} -//----------------------// - -void reader() {} - -void setup() { - Serial.begin(115200); - dmd.selectFont(Font_BOLD); +//------------------Wi-Fi Connection Setup-------------// +void setupWiFi() { WiFi.begin(ssid, password); - SPIFFS.begin(true); - pinMode(22, OUTPUT); - - //---Configured WebServer---// if (!WiFi.config(staticIP, gateway, subnet)) { Serial.println("Failed to configure Static IP"); } else { Serial.println("Static IP configured!"); } - //--------------------------// - //---Start file system---// - // File file = SPIFFS.open("/output.txt", "r"); - // if(!file){Serial.println("file open failed");} - // Serial.println("Содержимое файла:"); - // while(file.available()){ - // Serial.write(file.read()); - // } - // Serial.println(); - // file.close(); - - // File root = SPIFFS.open("/"); - // if(!root){ - // Serial.println("Ошибка открытия директории"); - // return; - // } - // if(!root.isDirectory()){ - // Serial.println("Не является директорией!"); - // return; - // } - - // File file = root.openNextFile(); - // while(file){ - // Serial.println(file.name()); - // file = root.openNextFile(); - //} - //-----------------------// - - //---Start the WiFi---// while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } + Serial.println("\nConnected to WiFi"); Serial.println(WiFi.localIP()); - //--------------------// +} +//-------------------------------------------------------// - //---Request to check the status of the panel---// - server.on("/api/led", HTTP_GET, [](AsyncWebServerRequest *request) { - request->send(200, "application/json", panel ? "{\"state\": \"true\"}" : "{\"state\": \"false\"}"); - }); - //----------------------------------------------// +//------------------Web Server Handlers-----------------// +void handleText(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) { + JsonDocument jsonReq; + String dataRequest = String((char *)data, len); + DeserializationError error = deserializeJson(jsonReq, dataRequest); - //---Request to change the status of the panel---// - /*server.on("/api/led", HTTP_POST, - [](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) - { - AsyncWebServerRequest *req = request; - Serial.println(String("data=") + (char*)data); - // // Serial.print(request); + if (error) { + Serial.println(F("deserializeJson() failed")); + request->send(400, "text/html", ""); + return; + } - // if (req->hasParam("plain", true)) { - // String panelState = req->getParam("panel", true)->value(); - // Serial.println(panelState); + if (jsonReq["text"].is()) { + displayText = jsonReq["text"].as(); + } - // if (panelState == "on") { - // Serial.println("Panel on!"); - // displayText = ""; - // panel = true; - // } else if (panelState == "off") { - // panel = false; - // Serial.println("Panel off!"); - // digitalWrite(22, LOW); - // dmd.clearScreen(1); - // displayText = ""; - // Serial.println("Screen clear"); - // } - // } - req->send(200, "text/html", ""); - });*/ + request->send(200, "text/html; charset=UTF-8", ""); +} - server.on( - "/api/led", HTTP_POST, - [](AsyncWebServerRequest *request) { - // Serial.println("1"); - // Serial.println(request->url() ); - // Serial.println(request->method()); - }, - [](AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final) { - //Serial.println("2"); - }, - [](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) { - String dataRequest = String((char *)data); - Serial.println(dataRequest); - if (dataRequest == "{\"panel\" : \"on\"}") { - Serial.println("Panel on"); - } else if (dataRequest == "{\"panel\" : \"off\"}") { - panel = false; - Serial.println("Panel off!"); - digitalWrite(22, LOW); - dmd.clearScreen(1); - displayText = ""; - Serial.println("Screen clear"); - } - request->send(200, "text/html", ""); - }); - //-----------------------------------------------// +void handleStateChange(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) { + JsonDocument jsonReq; + String dataRequest = String((char *)data, len); + DeserializationError error = deserializeJson(jsonReq, dataRequest); - //---A text modification request---// - server.on("/api/text", HTTP_POST, [](AsyncWebServerRequest *request) { - if (request->hasParam("text", true)) { - displayText = request->getParam("text", true)->value(); + if (error) { + request->send(400, "text/html", ""); + return; + } + + String state = jsonReq["state"]; + + if (state == "1") { + dmd.clearScreen(true); // Reset the screen + displayText = "Привет из СКБ \"КИТ\""; + } else if (state == "2") { + isScrolling = true; + lastScrollTime = millis(); + showImage = false; + } else if (state == "3") { + showImage = true; + imageStartTime = millis(); + } + + request->send(200, "text/html", ""); +} +//-------------------------------------------------------// + +//------------------Panel Management--------------------// +void handlePanelState(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) { + JsonDocument jsonReq; + String dataRequest = String((char *)data, len); + DeserializationError error = deserializeJson(jsonReq, dataRequest); + + if (error) { + request->send(400, "text/html", ""); + return; + } + + String state = jsonReq["panel"]; + if (state == "on") { + displayText = "Привет из СКБ \"КИТ\""; + } else if (state == "off") { + displayText = ""; + } + + request->send(200, "text/html", ""); +} +//-------------------------------------------------------// + +//------------------Display Binary Array Function------// +void displayBinaryArray() { + for (int y = 0; y < 32; y++) { + for (int x = 0; x < 16; x++) { + int idx = x * 32 + y; + if (output[idx] == 1) { + dmd.writePixel(x, y, GRAPHICS_NORMAL, true); + } else { + dmd.writePixel(x, y, GRAPHICS_NORMAL, false); + } } - request->send(200, "text/html; charset=UTF-8", - "

Text set to:

" + displayText + "

"); + } +} +//-------------------------------------------------------// + +//------------------Marquee Scroll Function-------------// +void scrollText() { + dmd.drawMarquee(displayText.c_str(), displayText.length(), (32 * DISPLAYS_ACROSS) - 1, 0); + + long start = millis(); + long timer = start; + bool ret = false; + + while (!ret) { + if ((timer + 30) < millis()) { + ret = dmd.stepMarquee(-1, 0); + timer = millis(); + } + } + + if (millis() - lastScrollTime >= scrollDuration) { + isScrolling = false; + showImage = true; + imageStartTime = millis(); + } +} +//-------------------------------------------------------// + +//------------------Timer Interrupt Function------------// +void IRAM_ATTR triggerScan() { + dmd.scanDisplayBySPI(); +} +//-------------------------------------------------------// + +//------------------Setup Function-----------------------// +void setup() { + Serial.begin(115200); + dmd.selectFont(FONT); + SPIFFS.begin(true); + pinMode(22, OUTPUT); + + setupWiFi(); + + server.on("/api/led", HTTP_GET, [](AsyncWebServerRequest *request) { + String state = isScrolling ? "true" : "false"; + request->send(200, "application/json", "{\"state\": \"" + state + "\"}"); }); - //---------------------------------// + + server.on("/api/led", HTTP_POST, [](AsyncWebServerRequest *request) {}, NULL, handlePanelState); + server.on("/api/text", HTTP_POST, [](AsyncWebServerRequest *request) {}, NULL, handleText); + server.on("/api/state", HTTP_POST, [](AsyncWebServerRequest *request) {}, NULL, handleStateChange); server.begin(); - //---Start the timer---// uint8_t cpuClock = ESP.getCpuFreqMHz(); timer = timerBegin(0, cpuClock, true); timerAttachInterrupt(timer, &triggerScan, true); timerAlarmWrite(timer, 300, true); timerAlarmEnable(timer); - //--------------------// - dmd.clearScreen(true); //Clearing the screen -} - -void loop() { - - //---Screen cleaning and text output---// dmd.clearScreen(true); - dmd.drawMarquee(displayText.c_str(), displayText.length(), (32 * DISPLAYS_ACROSS) - 1, 0); - //-------------------------------------// +} +//-------------------------------------------------------// - long start = millis(); - long timer = start; - boolean ret = false; +//------------------Loop Function------------------------// +void loop() { + dmd.clearScreen(true); - //---Scrolling text---// - while (!ret) { - if ((timer + 30) < millis()) { - ret = dmd.stepMarquee(-1, 0); // Прокрутка текста - timer = millis(); + if (isScrolling) { + scrollText(); + } + + if (showImage) { + displayBinaryArray(); + if (millis() - imageStartTime >= 5000) { + showImage = false; + isScrolling = true; + lastScrollTime = millis(); } } - //--------------------// + + delay(500); } +//-------------------------------------------------------//