
// https://github.com/me-no-dev/ESPAsyncTCP
// https://github.com/me-no-dev/AsyncTCP
// https://github.com/adafruit/Adafruit_NeoMatrix
// https://github.com/adafruit/Adafruit_NeoPixel


 // SPIFF Opload with PlatformIO  
 // pio run -t uploadfs

#include <ArduinoOTA.h>
#ifdef ESP32
#include <FS.h>
#include <SPIFFS.h>
#include <ESPmDNS.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESP8266mDNS.h>
#endif
#include <ESPAsyncWebServer.h>
#include <SPIFFSEditor.h>



// Adafruit_NeoMatrix example for tiled NeoPixel matrices.  Scrolls
// 'Howdy' across three 10x8 NeoPixel grids that were created using
// NeoPixel 60 LEDs per meter flex strip.

#include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>
#include "ILI9341_Colors.h"


#include "WiFiconig.inc"

// SKETCH BEGIN
AsyncWebServer server(80);
AsyncWebSocket ws("/neopixel");
AsyncEventSource events("/events");


// MATRIX DECLARATION:
// Parameter 1 = width of EACH NEOPIXEL MATRIX (not total display)
// Parameter 2 = height of each matrix
// Parameter 3 = number of matrices arranged horizontally
// Parameter 4 = number of matrices arranged vertically
// Parameter 5 = pin number (most are valid)
// Parameter 6 = matrix layout flags, add together as needed:
//   NEO_MATRIX_TOP, NEO_MATRIX_BOTTOM, NEO_MATRIX_LEFT, NEO_MATRIX_RIGHT:
//     Position of the FIRST LED in the FIRST MATRIX; pick two, e.g.
//     NEO_MATRIX_TOP + NEO_MATRIX_LEFT for the top-left corner.
//   NEO_MATRIX_ROWS, NEO_MATRIX_COLUMNS: LEDs WITHIN EACH MATRIX are
//     arranged in horizontal rows or in vertical columns, respectively;
//     pick one or the other.
//   NEO_MATRIX_PROGRESSIVE, NEO_MATRIX_ZIGZAG: all rows/columns WITHIN
//     EACH MATRIX proceed in the same order, or alternate lines reverse
//     direction; pick one.
//   NEO_TILE_TOP, NEO_TILE_BOTTOM, NEO_TILE_LEFT, NEO_TILE_RIGHT:
//     Position of the FIRST MATRIX (tile) in the OVERALL DISPLAY; pick
//     two, e.g. NEO_TILE_TOP + NEO_TILE_LEFT for the top-left corner.
//   NEO_TILE_ROWS, NEO_TILE_COLUMNS: the matrices in the OVERALL DISPLAY
//     are arranged in horizontal rows or in vertical columns, respectively;
//     pick one or the other.
//   NEO_TILE_PROGRESSIVE, NEO_TILE_ZIGZAG: the ROWS/COLUMS OF MATRICES
//     (tiles) in the OVERALL DISPLAY proceed in the same order for every
//     line, or alternate lines reverse direction; pick one.  When using
//     zig-zag order, the orientation of the matrices in alternate rows
//     will be rotated 180 degrees (this is normal -- simplifies wiring).
//   See example below for these values in action.
// Parameter 7 = pixel type flags, add together as needed:
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 pixels)
//   NEO_GRB     Pixels are wired for GRB bitstream (v2 pixels)
//   NEO_KHZ400  400 KHz bitstream (e.g. FLORA v1 pixels)
//   NEO_KHZ800  800 KHz bitstream (e.g. High Density LED strip)

// Example with three 10x8 matrices (created using NeoPixel flex strip --
// these grids are not a ready-made product).  In this application we'd
// like to arrange the three matrices side-by-side in a wide display.
// The first matrix (tile) will be at the left, and the first pixel within
// that matrix is at the top left.  The matrices use zig-zag line ordering.
// There's only one row here, so it doesn't matter if we declare it in row
// or column order.  The matrices use 800 KHz (v2) pixels that expect GRB
// color data.

Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(  NeoPixelTileWidth, NeoPixelTileHeight, NeoTilesModulesX, NeoTilesModulesY, NeoPixelPIN,

//Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(NeoPixelTileWidth, NeoPixelTileHeight, 3, 1, NeoPixelPIN,
  
  NEO_MATRIX_BOTTOM    + NEO_MATRIX_LEFT +
  NEO_MATRIX_ROWS + NEO_MATRIX_PROGRESSIVE +

  NEO_TILE_TOP + NEO_TILE_LEFT + NEO_TILE_COLUMNS + NEO_TILE_PROGRESSIVE ,


  NEO_GRBW + NEO_KHZ800);

const uint16_t colors[] = {
  matrix.Color(255, 0, 0), matrix.Color(0, 255, 0), matrix.Color(0, 0, 255) 
  };

uint16_t RGB32_2RGB16(String Value)
{
  Value.replace("hex","");
    uint32_t rgb32 = strtoul(Value.c_str(), 0, 16);
  //Serial.printf("-----> %s <----§§§####> %d <-----", Value.c_str(), rgb32 );
    return (rgb32 >> 8 & 0xf800) | (rgb32 >> 5 & 0x07e0) | (rgb32 >> 3 & 0x001f);
}

void InitPorts();
void SetupNeoPixel();
void SetupOTA();
void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len);
void connectToWiFi(const char * ssid, const char * pwd);
void SetupServer();
String HTML_Processor(const String& var);


//// NeoPixel Pattern
void NeoPixelTest();
void NeoPixelPattern1();
void NeoPixelPattern2();
void NeoPixelPattern3();
void NeoPixelPattern4();
void NeoPixelPattern5();
void NeoPixelPattern6();
void NeoPixelPattern7();
void NeoPixelPattern8();
void NeoPixelPattern9();
void NeoPixelPattern10();
void NeoPixelPattern11();
void NeoPixelPattern12();

void CheckPattern(MatrixMessage_s Value);
void NeoPixelText1(const MatrixMessage_s Value);
MatrixMessage_s GetMatrixTextValues(String Value);


/*********************************************************************************
* @brief  setup()
* @return none
*********************************************************************************/
void setup() {
   Serial.begin(115200);
   Serial.setDebugOutput(true);
   ESP.wdtDisable();
   InitPorts();

    connectToWiFi(ssid, password);
    SetupServer();
    SetupOTA();
    SetupNeoPixel(); 
    NeoPixelTest();

    ESP.wdtEnable(1000);
}



void loop() {
  ESP.wdtFeed();
  if (ColorRGB16 != MerkerColorRGB16)
  {
  matrix.fillRect(0,0, NeoPixelMatrixWidth, NeoPixelTileHeight,ColorRGB16);
  matrix.show();
  delay(50);
  MerkerColorRGB16 = ColorRGB16;
  
  }
   ArduinoOTA.handle();
 if (sWebSocket.bTriggerWebsocketMsg)
 {
sWebSocket.bTriggerWebsocketMsg = false;
sprintf(Buffer, "[Status] %s", sWebSocket.WebsocketMsg.c_str()  );

 Serial.printf ("[in Loop ---- > %s -Trigger: %d--Color : 0x%x -- Bkg 0x%x --- Pattern : %d --- \n", sMatrixMessage.Text.c_str(), sMatrixMessage.bTriggerPattern, sMatrixMessage.Color, sMatrixMessage.BkgColor, sMatrixMessage.Pattern);
ws.printf(ClientID, Buffer );
events.send("In the Loop",NULL,millis(),500);
 }

CheckPattern(sMatrixMessage);
   ws.cleanupClients();

   if (ToggleCounter++ > 10000)
{
   ToggleCounter = 0;
   TOGGLE(LedStatus1);
}
}



void InitPorts()
{

pinMode( LedStatus1, OUTPUT);
pinMode( LedStatus2, OUTPUT);

}



/*********************************************************************************
* @brief  CheckPattern
* @return none
*********************************************************************************/
void CheckPattern(MatrixMessage_s Value)
{

if ( Value.bTriggerPattern)
{
 TOGGLE(LedStatus2);
 Serial.printf ("[---- > %s -Trigger: %d--Color : 0x%x -- Bkg 0x%x --- Pattern : %d --- \n", Value.Text.c_str(), Value.bTriggerPattern, Value.Color, Value.BkgColor, Value.Pattern);
ws.printf(ClientID, "[BuDisable]" );

switch (Value.Pattern)
{
case 1: NeoPixelPattern1();    break;
case 2: NeoPixelPattern2();    break;
case 3: NeoPixelPattern3();    break;
case 4: NeoPixelPattern4();    break;
case 5: NeoPixelPattern5();    break;
case 6: NeoPixelPattern6();    break;
case 7: NeoPixelPattern7();    break;
case 8: NeoPixelPattern8();    break;
case 9: NeoPixelPattern9();    break;
case 10: NeoPixelPattern10();    break;
case 11: NeoPixelPattern11();    break;
case 12: NeoPixelPattern12();    break;
case 13: NeoPixelText1(Value);    break;

default:
  break;
}

matrix.fillScreen(ILI9341_BLACK);
matrix.show();

sMatrixMessage.bTriggerPattern = false; // We can change this later
ws.printf(ClientID, "[BuEnable]" );
}
}

/*********************************************************************************
* @brief  SetupNeoPixel()
* @return none
*********************************************************************************/
void SetupNeoPixel()
{
  matrix.begin();
  matrix.setTextWrap(false);
  matrix.setBrightness(20);
  matrix.setTextColor(colors[0]);
}


/*********************************************************************************
* @brief  connectToWiFi
* @return none
*********************************************************************************/
void connectToWiFi(const char * ssid, const char * pwd)
{
    	Serial.printf(Buffer, "Connecting to WiFi network : %s", ssid);

  // delete old config
  WiFi.disconnect(true);
   WiFi.hostname(hostName);

 if (!WiFi.config(staticIP, gateway, subnet, dns1, dns2)) 
 {
 Serial.println("STA Failed to configure");
 }

  //Initiate connection
  WiFi.begin(ssid, pwd);

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(150);
    Serial.print(".");
  }

 sIPAddress =  WiFi.localIP().toString();

 Serial.printf("*************************IP Adresse %s ********************\n", sIPAddress.c_str());
   }


/*********************************************************************************
* @brief  SetupOTA()
* @return none
*********************************************************************************/
void SetupOTA()
{
  //Send OTA events to the browser
  ArduinoOTA.onStart([]() { events.send("Update Start", "ota"); });
  ArduinoOTA.onEnd([]() { events.send("Update End", "ota"); });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    char p[32];
    sprintf(p, "Progress: %u%%\n", (progress/(total/100)));
    events.send(p, "ota");
  });
  ArduinoOTA.onError([](ota_error_t error) {
    if(error == OTA_AUTH_ERROR) events.send("Auth Failed", "ota");
    else if(error == OTA_BEGIN_ERROR) events.send("Begin Failed", "ota");
    else if(error == OTA_CONNECT_ERROR) events.send("Connect Failed", "ota");
    else if(error == OTA_RECEIVE_ERROR) events.send("Recieve Failed", "ota");
    else if(error == OTA_END_ERROR) events.send("End Failed", "ota");
  });
  ArduinoOTA.setHostname(hostName);
  ArduinoOTA.begin();
}

void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len)
{
  if(type == WS_EVT_CONNECT){
    Serial.printf("ws[%s][%u] connect\n", server->url(), client->id());
    client->printf("***> Hello Client %u :)", client->id());
     ClientID = client->id();

    client->ping();
  } else if(type == WS_EVT_DISCONNECT){
    Serial.printf("ws[%s][%u] disconnect\n", server->url(), client->id());
  } else if(type == WS_EVT_ERROR){
    Serial.printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t*)arg), (char*)data);
  } else if(type == WS_EVT_PONG){
    Serial.printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len)?(char*)data:"");
  } else if(type == WS_EVT_DATA){
    AwsFrameInfo * info = (AwsFrameInfo*)arg;
    String msg = "";
    if(info->final && info->index == 0 && info->len == len){
      //the whole message is in a single frame and we got all of it's data
      Serial.printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT)?"text":"binary", info->len);

      if(info->opcode == WS_TEXT){
        for(size_t i=0; i < info->len; i++) {
          msg += (char) data[i];
        }
      } else {
        char buff[3];
        for(size_t i=0; i < info->len; i++) {
          sprintf(buff, "%02x ", (uint8_t) data[i]);
          msg += buff ;
        }
      }
      Serial.printf("%s\n",msg.c_str());

      if(info->opcode == WS_TEXT)
        client->text("I got your text message");
      else
        client->binary("I got your binary message");
    } else {
      //message is comprised of multiple frames or the frame is split into multiple packets
      if(info->index == 0){
        if(info->num == 0)
          Serial.printf("ws[%s][%u] %s-message start\n", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary");
        Serial.printf("ws[%s][%u] frame[%u] start[%llu]\n", server->url(), client->id(), info->num, info->len);
      }

      Serial.printf("ws[%s][%u] frame[%u] %s[%llu - %llu]: ", server->url(), client->id(), info->num, (info->message_opcode == WS_TEXT)?"text":"binary", info->index, info->index + len);

      if(info->opcode == WS_TEXT){
        for(size_t i=0; i < len; i++) {
          msg += (char) data[i];
        }
      } else {
        char buff[3];
        for(size_t i=0; i < len; i++) {
          sprintf(buff, "%02x ", (uint8_t) data[i]);
          msg += buff ;
        }
      }
      Serial.printf("%s\n",msg.c_str());

      if((info->index + len) == info->len){
        Serial.printf("ws[%s][%u] frame[%u] end[%llu]\n", server->url(), client->id(), info->num, info->len);
        if(info->final){
          Serial.printf("ws[%s][%u] %s-message end\n", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary");
          if(info->message_opcode == WS_TEXT)
            client->text("I got your text message");
          else
            client->binary("I got your binary message");
        }
      }
    }
  }
}


/*********************************************************************************
* @brief  SetupServer() Webserver
* @return none
*********************************************************************************/

void SetupServer()
 {
  SPIFFS.begin();

  ws.onEvent(onWsEvent);
  server.addHandler(&ws);

  events.onConnect([](AsyncEventSourceClient *client){
   client->send( "hello!",NULL,millis(),1000);
   });
  server.addHandler(&events);





#ifdef ESP32
  server.addHandler(new SPIFFSEditor(SPIFFS, http_username,http_password));
#elif defined(ESP8266)
  server.addHandler(new SPIFFSEditor(http_username,http_password));
#endif


  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/index.html" , String(), false, HTML_Processor);
  });

  
  server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.html");
  // Route to load style.css file
  server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/style.css" , "text/css");
  });


  server.on("/java_script.js", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/java_script.js" , "text/javascript");
  });

  server.on("/java_script2.js", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/java_script2.js" , "text/javascript");
  });
 
  server.on("/color.jpg", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/color.jpg", "image/jpg");
    });

  server.on("/color1.png", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/color1.png", "image/png");
    });    

  server.on("/color2.png", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/color2.png", "image/png");
    });    

  server.on("/color3.png", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/color3.png", "image/png");
    });    


     server.on("/favicon.ico", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/favicon.ico", "image/x-icon"); 
     }); 



  server.on("/color1", HTTP_GET, [] (AsyncWebServerRequest *request) {
    String inputMessage1;
    if (request->hasParam("rgb"))  {
      inputMessage1 = request->getParam("rgb")->value();
      }    else
    inputMessage1 = "No message sent - rgb";
      
   Serial.println(inputMessage1);

 if (inputMessage1.startsWith("hex"))
   ColorRGB16 = RGB32_2RGB16(inputMessage1);
    request->send(200, "/buttons","OK" );
  });


server.on("/color2", HTTP_GET, [] (AsyncWebServerRequest *request) {
    String inputMessage1;
    if (request->hasParam("rgba"))  {
      inputMessage1 = request->getParam("rgba")->value();
      }    else
    inputMessage1 = "No message sent - rgba";
      
   Serial.println(inputMessage1);
  

    request->send(200, "/buttons","OK" );
  });


server.on("/pattern", HTTP_GET, [] (AsyncWebServerRequest *request) {
    String inputMessage1;
    if (request->hasParam("simple"))  {
      inputMessage1 = request->getParam("simple")->value();
      sMatrixMessage.bTriggerPattern = true;
      sMatrixMessage.Text = inputMessage1;
      sWebSocket.bTriggerWebsocketMsg = true;

      sWebSocket.WebsocketMsg = inputMessage1;
    
      int num = inputMessage1.toInt();
      sMatrixMessage.Pattern = num;    
    
 Serial.printf ("pattern ---- > %s -Trigger: %d--Color : 0x%x -- Bkg 0x%x --- Pattern : %d --- \n", sMatrixMessage.Text.c_str(), sMatrixMessage.bTriggerPattern, sMatrixMessage.Color, sMatrixMessage.BkgColor, sMatrixMessage.Pattern);
      
     
      }    else
    inputMessage1 = "No message sent - Simple";

    request->send(200, "/buttons","[TestXYZ] Martin Michael " );
  });


server.on("/neopat", HTTP_GET, [] (AsyncWebServerRequest *request) {
    String inputMessage1;
    if (request->hasParam("simple"))  {

      inputMessage1 = request->getParam("simple")->value();
      sMatrixMessage = GetMatrixTextValues(inputMessage1);
      Serial.printf("input Msg : %s -Matrix- >> %s - %d - %d ", inputMessage1.c_str(), sMatrixMessage.Text.c_str(), sMatrixMessage.Color, sMatrixMessage.BkgColor);

       sMatrixMessage.Pattern = 13; // Becaue we don't get it as Message
    
         sMatrixMessage.bTriggerPattern = true;
       sWebSocket.bTriggerWebsocketMsg = true;


     sWebSocket.WebsocketMsg = inputMessage1;
 
      }    else
    inputMessage1 = "No message sent - Simple";
    
    request->send(200, "/neopat","[Test] Das ist ein Test" );
  });




  server.onNotFound([](AsyncWebServerRequest *request){
    Serial.printf("NOT_FOUND: ");
    if(request->method() == HTTP_GET)
      Serial.printf("GET");
    else if(request->method() == HTTP_POST)
      Serial.printf("POST");
    else if(request->method() == HTTP_DELETE)
      Serial.printf("DELETE");
    else if(request->method() == HTTP_PUT)
      Serial.printf("PUT");
    else if(request->method() == HTTP_PATCH)
      Serial.printf("PATCH");
    else if(request->method() == HTTP_HEAD)
      Serial.printf("HEAD");
    else if(request->method() == HTTP_OPTIONS)
      Serial.printf("OPTIONS");
    else
      Serial.printf("UNKNOWN");
    Serial.printf(" http://%s%s\n", request->host().c_str(), request->url().c_str());

    if(request->contentLength()){
      Serial.printf("_CONTENT_TYPE: %s\n", request->contentType().c_str());
      Serial.printf("_CONTENT_LENGTH: %u\n", request->contentLength());
    }

    int headers = request->headers();
    int i;
    for(i=0;i<headers;i++){
      AsyncWebHeader* h = request->getHeader(i);
      Serial.printf("_HEADER[%s]: %s\n", h->name().c_str(), h->value().c_str());
    }

    int params = request->params();
    for(i=0;i<params;i++){
      AsyncWebParameter* p = request->getParam(i);
      if(p->isFile()){
        Serial.printf("_FILE[%s]: %s, size: %u\n", p->name().c_str(), p->value().c_str(), p->size());
      } else if(p->isPost()){
        Serial.printf("_POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
      } else {
        Serial.printf("_GET[%s]: %s\n", p->name().c_str(), p->value().c_str());
      }
    }

    request->send(404);
  });
  server.onFileUpload([](AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final){
    if(!index)
      Serial.printf("UploadStart: %s\n", filename.c_str());
    Serial.printf("%s", (const char*)data);
    if(final)
      Serial.printf("UploadEnd: %s (%u)\n", filename.c_str(), index+len);
  });
  server.onRequestBody([](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){
    if(!index)
      Serial.printf("BodyStart: %u\n", total);
    Serial.printf("%s", (const char*)data);
    if(index + len == total)
      Serial.printf("BodyEnd: %u\n", total);
  });
  server.begin();
}

/*********************************************************************************
* @brief  HTML_Processor(const String& var) For the HTML Webpage Values
* @param  var the Value to change
* @return String
*********************************************************************************/
String HTML_Processor(const String& var)
{
  String Status = "";
  Serial.print("----------- > ");
  Serial.println(var);
 
   if (var ==  "IP_ADRESSE")
  Status = sIPAddress; 
   
 return (Status);
}


/*********************************************************************************
* @brief  GetRedish() in RGB16 565
* @param  none
* @return none
*********************************************************************************/
uint16_t GetRedish()
{
    uint16_t Result;
    Result = rand() % 0b11111;
    
    Result <<= 11;
     return (Result);
}

/*********************************************************************************
* @brief  GetGreenish() in RGB16 565
* @param  none
* @return none
*********************************************************************************/
uint16_t GetGreenish()
{
    uint16_t Result;
    Result = rand() % 0b11111;
    Result <<= 6;
    return (Result);
}

/*********************************************************************************
* @brief  GetBlueish() in RGB16 565
* @param  none
* @return none
*********************************************************************************/
uint16_t GetBlueish()
{
    uint16_t Result;
    Result = rand() % 0b11111;
    return (Result);
}



/*********************************************************************************
* @brief  NeoPixelTest() Just a Test with matrix
* @param  none
* @return none
*********************************************************************************/
void NeoPixelTest()
{

for (int y = 0; y < NeoPixelTileHeight; y++)
for (int x = 0; x < NeoPixelMatrixWidth; x++) {
matrix.drawPixel(x, y, ILI9341_WHITE);
matrix.show();
delay(Delay10);
ESP.wdtFeed();
matrix.drawPixel(x, y, ILI9341_BLACK );
matrix.show();

}

}


/*********************************************************************************
* @brief  NeoPixelPattern1() Just a Test with matrix
* @param  none
* @return none
*********************************************************************************/
void NeoPixelPattern1()
{

for (int y = 0; y < NeoPixelTileHeight; y++)
for (int x = 0; x <  NeoPixelMatrixWidth; x++) {
matrix.drawPixel(x, y, ILI9341_ORANGE );
matrix.show();
delay(Delay10);
ESP.wdtFeed();
}

for (int y = NeoPixelTileHeight; y >= 0; y--)
for (int x =  NeoPixelMatrixWidth; x >= 0; x--) {
matrix.drawPixel(x, y, ILI9341_BLACK );
matrix.show();
delay(Delay10);

}
}

/*********************************************************************************
* @brief  NeoPixelPattern2() Draw short Snake over the Screen
* @param  none
* @return none
*********************************************************************************/
void NeoPixelPattern2()
{

for (int y = 0; y < NeoPixelTileHeight; y++)
for (int x = 0; x <  NeoPixelMatrixWidth; x++) {
matrix.drawPixel(x, y, ILI9341_RED );
matrix.drawPixel(x+1, y, ILI9341_BLUE );
matrix.drawPixel(x+2, y, ILI9341_BLUE );
matrix.drawPixel(x+3, y, ILI9341_RED );
matrix.show();
delay(Delay10);
ESP.wdtFeed();
matrix.drawPixel(x, y, ILI9341_BLACK );
matrix.drawPixel(x+1, y, ILI9341_BLACK );
matrix.drawPixel(x+2, y, ILI9341_BLACK );
matrix.drawPixel(x+3, y, ILI9341_BLACK );
matrix.show();

}
}

/*********************************************************************************
* @brief  NeoPixelPattern4() Fill Springle of Pixel
* @param  none
* @return none
*********************************************************************************/
void NeoPixelPattern3()
{
int i = 0;
while (i < 1000)
{
uint16_t x = rand() %  NeoPixelMatrixWidth; 
uint16_t y = rand() % NeoPixelTileHeight;

uint16_t Color = rand() % 0x1fff;
matrix.drawPixel(x, y, Color );
matrix.show();
delay(Delay10);
ESP.wdtFeed();
i++;
}
matrix.fillScreen(ILI9341_BLACK);
}

/*********************************************************************************
* @brief  NeoPixelPattern4() Draw Springle of Pixel
* @param  none
* @return none
*********************************************************************************/
void NeoPixelPattern4()
{
int i = 0;
while (i < 1000)
{
uint16_t x = rand() %  NeoPixelMatrixWidth; 
uint16_t y = rand() % NeoPixelTileHeight;

uint16_t Color = rand() % 0xffff;
matrix.drawPixel(x, y, Color );
matrix.show();
delay(10);
ESP.wdtFeed();
matrix.drawPixel(x, y, ILI9341_BLACK );
matrix.show();
i++;
}
}

/*********************************************************************************
* @brief  NeoPixelPattern7() Draw Pulsing Red Screen
* @param  none
* @return none
*********************************************************************************/
void NeoPixelPattern5()
{
int i = 0;
while (i < 500)
{
matrix.fillScreen( GetRedish());
delay(Delay10);
ESP.wdtFeed();
i++;
}
matrix.fillScreen(ILI9341_BLACK);
}

/*********************************************************************************
* @brief  NeoPixelPattern7() Draw Pulsing Blue Screen
* @param  none
* @return none
*********************************************************************************/
void NeoPixelPattern6()
{
int i = 0;
while (i < 500)
{
matrix.fillScreen( GetBlueish());
delay(Delay10);
ESP.wdtFeed();
i++;
}
}

/*********************************************************************************
* @brief  NeoPixelPattern7() Draw Pulsing Green Screen
* @param  none
* @return none
*********************************************************************************/
void NeoPixelPattern7()
{
int i = 0;
while (i < 500)
{
matrix.fillScreen( GetGreenish());
delay(Delay10);
ESP.wdtFeed();
i++;
}
}


/*********************************************************************************
* @brief  NeoPixelPattern8() Draw Pulsing Red Rects
* @param  none
* @return none
*********************************************************************************/
void NeoPixelPattern8()
{
for (int c = 0; c < 25; c++)
for (int i = 0; i < NeoPixelTileHeight; i++){
matrix.drawRect(i,i, NeoPixelMatrixWidth - i , NeoPixelTileHeight - i , GetRedish());
delay(Delay25);
ESP.wdtFeed();
matrix.show();
}
}



/*********************************************************************************
* @brief  NeoPixelPattern9() Draw Pulsing Red Rects
* @param  none
* @return none
*********************************************************************************/
void NeoPixelPattern9()
{

int counter = 0;

while (counter++ < 100)
{

for (int i = 0; i < NeoPixelTileHeight; i++){
matrix.drawRect(i,i, NeoPixelMatrixWidth - i , NeoPixelTileHeight - i , GetRedish());
delay(Delay10);
ESP.wdtFeed();
matrix.show();
}

matrix.fillScreen(ILI9341_BLACK);
for (int i = NeoPixelTileHeight; i>0; i--){
matrix.drawRect(i,i, NeoPixelMatrixWidth - i , NeoPixelTileHeight - i , GetRedish());
delay(Delay10);
ESP.wdtFeed();
matrix.show();
}

}
}

/*********************************************************************************
* @brief  NeoPixelPattern10() Draw Lines
* @param  none
* @return none
*********************************************************************************/
void NeoPixelPattern10()
{


for (int i = 0; i < 3; i++) {
for (int x = -4; x <  NeoPixelMatrixWidth +3; x++) {
matrix.drawFastVLine(x, 0, NeoPixelTileHeight, ILI9341_RED );
matrix.drawFastVLine(x+1, 0, NeoPixelTileHeight, ILI9341_BLUE );
matrix.drawFastVLine(x+2, 0, NeoPixelTileHeight, ILI9341_BLUE );
matrix.drawFastVLine(x+3, 0, NeoPixelTileHeight, ILI9341_RED );

matrix.show();
delay(Delay25);
ESP.wdtFeed();

matrix.drawFastVLine(x, 0, NeoPixelTileHeight, ILI9341_BLACK );
matrix.drawFastVLine(x+1, 0, NeoPixelTileHeight, ILI9341_BLACK );
matrix.drawFastVLine(x+2, 0, NeoPixelTileHeight, ILI9341_BLACK );
matrix.drawFastVLine(x+3, 0, NeoPixelTileHeight, ILI9341_BLACK );
matrix.show();
}


for (int x =  NeoPixelMatrixWidth +3; x > -4; x--) {
matrix.drawFastVLine(x, 0, NeoPixelTileHeight, ILI9341_RED );
matrix.drawFastVLine(x+1, 0, NeoPixelTileHeight, ILI9341_BLUE );
matrix.drawFastVLine(x+2, 0, NeoPixelTileHeight, ILI9341_BLUE );
matrix.drawFastVLine(x+3, 0, NeoPixelTileHeight, ILI9341_RED );

matrix.show();
delay(Delay25);
ESP.wdtFeed();

matrix.drawFastVLine(x, 0, NeoPixelTileHeight, ILI9341_BLACK );
matrix.drawFastVLine(x+1, 0, NeoPixelTileHeight, ILI9341_BLACK );
matrix.drawFastVLine(x+2, 0, NeoPixelTileHeight, ILI9341_BLACK );
matrix.drawFastVLine(x+3, 0, NeoPixelTileHeight, ILI9341_BLACK );
matrix.show();
} }

}

/*********************************************************************************
* @brief  NeoPixelPattern11() Draw Lines
* @param  none
* @return none
*********************************************************************************/
void NeoPixelPattern11()
{
for (int i = 0; i < 10; i++)  {  
for (int x = 0; x <  NeoPixelMatrixWidth; x++) 
{
matrix.drawFastVLine(x,0,NeoPixelTileHeight, rand() % 0xffff );
matrix.show();
delay(Delay25);
ESP.wdtFeed();
matrix.drawFastVLine(x,0,NeoPixelTileHeight, ILI9341_BLACK );
matrix.show();
}

for (int x =  NeoPixelMatrixWidth; x > 0; x--) 
{
matrix.drawFastVLine(x,0,NeoPixelTileHeight, rand() % 0xffff );
matrix.show();
delay(Delay25);
ESP.wdtFeed();
matrix.drawFastVLine(x,0,NeoPixelTileHeight, ILI9341_BLACK );
matrix.show();
}
}}

/*********************************************************************************
* @brief  NeoPixelPattern12() Draw Lines
* @param  none
* @return none
*********************************************************************************/
void NeoPixelPattern12()
{

for (int i = 0; i < 5; i++)  {
for (int x = 0; x <  NeoPixelMatrixWidth; x++) 
{
matrix.drawFastVLine(x,0,NeoPixelTileHeight, rand() % 0xffff );
matrix.show();
delay(Delay25);
ESP.wdtFeed();
}

for (int x =  NeoPixelMatrixWidth; x > 0; x--) 
{
matrix.drawFastVLine(x,0,NeoPixelTileHeight, rand() % 0xffff );
matrix.show();
delay(Delay25);
}}}


/*********************************************************************************
* @brief  NeoPixelText1(const char Text[], uint16_t Color, uint16_t BkgColor)
* @param  Text to display
* @param  Color Text Color
* @param  BkgColor Background Color
* @return none
*********************************************************************************/
 void NeoPixelText1(const MatrixMessage_s Value)
{
 
  matrix.setTextColor(Value.Color,Value.BkgColor);
  strcpy(Buffer,Value.Text.c_str());
  int l = (strlen(Buffer) * 5 + NeoPixelMatrixWidth) *-1;
 
 for (int x =  NeoPixelMatrixWidth; x > l; x--)
 { 
 matrix.fillScreen(ILI9341_BLACK);
  matrix.setCursor(x, 0);
  matrix.print(Buffer);
  matrix.show();
  delay(Delay100);
  ESP.wdtFeed();
 }
 
  matrix.fillScreen(ILI9341_BLACK);
}


/*********************************************************************************
* @brief  HexStr2Int
* @param  Value Hexstring
* @return integer
*********************************************************************************/
uint32_t HexStr2Int(String Value)
{
    uint32_t Result = 0;
    char* p;
    Result = strtol(Value.c_str(), &p, 16);
        return (Result);
  }


/*********************************************************************************
* @brief  GetMatrixTextValues
* @param  Value String from index HTML 
* @return struct
*********************************************************************************/
MatrixMessage_s GetMatrixTextValues(String Value)
{
MatrixMessage_s Result;
int  num;
String S;
uint16_t d1,d2;
if (Value.startsWith("[Text]") )
{

 num = Value.indexOf("=");
 Value.remove(0, num + 1);
 Value.trim();
 
 num = Value.indexOf("[Color]");
 Result.Text = Value.substring(0, num);
 Result.Text.trim();
 num = Value.indexOf("=");
 Value.remove(0,num + 1);
 num = Value.indexOf("[Bkg]");
 S = Value.substring(0, num);
 S.trim();
 d1 =  RGB32_2RGB16(S);
 Result.Color = d1;
 
num = Value.indexOf("=");
Value.remove(0,num +1);
Value.trim();
d2 = RGB32_2RGB16(Value);
Result.BkgColor = d2;
Serial.printf( "RGB16 - %d - %d", d1, d2);

}
return Result;
}




