Tony
Published © GPL3+

Smart matrix LED display

A fully integrated matrix LED display with microcontroller wi-fi connected and motion detector sensor.

BeginnerWork in progressOver 1 day2,510
Smart matrix LED display

Things used in this project

Hardware components

Espressif ESP-WROOM-32
×1
MAX7219 Dot Matrix Module 4 in 1
×3
Proximity Sensor- Pyroelectric Infrared Sensor Module
KEMET Electronics Corporation Proximity Sensor- Pyroelectric Infrared Sensor Module
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Tape, Electrical Insulation
Tape, Electrical Insulation

Story

Read more

Schematics

ESP32 WROOM 32 PINOUT

ESP WROOM 32 LEDs

MAX 7291 Size

MAX 7291 Electric schema

Code

Define.h

C/C++
Variables used in the program
static const String APP_NAME = "T-Time";
static const String APP_VERSION = "V.1.0";
static const String APP_DATE = "01/03/2020";

// Define the number of devices we have in the chain and the hardware interface
#define  MAX_DEVICES 12

#define CLK_PIN   14
#define DATA_PIN  12
#define CS_PIN    15
#define KEMET_PIN 25

#define AP_WIFI_SSID "LCD_SETUP"
#define AP_WIFI_PASSWD "XXXXXXXX"
#define ONBOARDLED 2 // Built in LED on ESP32 Node MCU
#define SPEED_TIME  14
#define INTENSITY  1
#define ALLERT_DURATION  25 //5 seconds = 200 ms * 25 allert_scorri
#define WEB_UPDATE 1 //minuti
unsigned long TIMEOUT_WEB = 15000; //milliseconds

#if DEBUG_TT
#define DEBUG_START Serial.begin(115200); Serial.println("Serial started @ 115200");
#define DEBUG_PRINT(x)    Serial.print (x)
#define DEBUG_PRINTDEC(x) Serial.print (x, DEC)
#define DEBUG_PRINTLN(x)  Serial.println (x)
#define DEBUG_PRINTLN2(x,y)  Serial.println (x,y)
#define DEBUG_PRINTF1(x,y)  Serial.printf (x,y)
#define DEBUG_PRINTF2(x,y,z)  Serial.printf (x,y,z)
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTDEC(x)
#define DEBUG_PRINTLN(x)
#define DEBUG_PRINTLN2(x,y)
#define DEBUG_PRINTF1(x,y)
#define DEBUG_PRINTF2(x,y,z)
#define DEBUG_START
#endif

// number of items in an array
#define NUMITEMS(arg) ((unsigned int) (sizeof (arg) / sizeof (arg [0])))

template< typename T, size_t N > size_t ArraySize (T (&) [N]) {
  return N;
}

TaskHandle_t Task1;
TaskHandle_t Task2;
TaskHandle_t Task3;

AsyncWebServer server(80);

const String WIFIs[] = {"ID1XXXX", "PWD1XXXX","ID2XXXX", "PWD2XXXX"}; //add all wifi connection that you need


int8_t intensity = INTENSITY; //display intensity
int8_t speed = SPEED_TIME; //display speed time
int8_t allertDuration = ALLERT_DURATION; //display speed time

int8_t timeZone = 1;
int8_t minutesTimeZone = 0;
int8_t wifi = 0;
String ip = "IP NONE";
bool displayIP = true;
bool autostdbyActivate = true;
bool display_airbus_news = false;

//Multicore code
static int taskCore0 = 0;
static int taskCore1 = 1;

uint32_t lastTimeNews = 0;   // millis() memory
long randNumber = 0;


// Read all the lines of the reply from server
#define MAX_LUNGH_RICERCA 512
#define MAX_MESG  300
char* ric = new char[MAX_LUNGH_RICERCA];
char* trovato = new char[MAX_MESG];

/*START NEWS NEWS*/
#define MAX_NEWS 20
uint32_t refresh_news_now = 10000;
uint8_t PREF_refresh_news_in_minutes = 30;
String NEWS_news[MAX_NEWS];
int NEWS_news_salvate = 0;
int NEWS_news_scorri = 0;
//http://feeds.bbci.co.uk/news/world/rss.xml
//http://www.NEWSimes.com/svc/collections/v1/publish/https://www.NEWSimes.com/section/world/rss.xml
String servernameNEWS = "feeds.bbci.co.uk"; // remote server we will connect to
String urlNEWS = "/news/world/rss.xml";



//DISPLAY

uint8_t STATO_SCENA_LOOP_2 = 0;

#define  PAUSE_TIME  0

String CityID = "3180990";
String lang = "EN";
String APIKEY = "XXXXXXXXXXXXXXXXXXXXX"; //put your apikey here
const char* City[] = {"Roma,it"};
int CityInd = 0;
char* servername = "api.openweathermap.org"; // remote server we will connect to


// Global variables
uint8_t  STATO_SCENA_LOOP_1 = 0;    // current display mode
uint8_t STATO_SCORRI_PACMAN = 0;
bool STATO_GET_DISPLAY_ON = true;
char  szSolo[9];    // mm:ss\0
char  szMesg[MAX_MESG];
String message = String(APP_NAME) + " " + APP_VERSION; // a String to hold incoming data
boolean allertOn = false;
String allert = "ATTENZIONE!!!"; // a String to hold incoming data
char cmd[128] = "set time yyyy-mm-dd hh:mm:ss";
String meteo = " Meteo NaN";
String icon = "$";
uint8_t STATO_SCORRI_ALLERT = 0;
const uint8_t CONST_DISPLAY_MAX_LINES = 12 * 8;
char VAR_BARRA_STRING[2] = {0 , '\0'}; 
uint8_t lines_now = 0;
uint8_t lines_next = 0;

uint32_t timer[] = {0 , 0}; // { now secs , end secs }
boolean timer_on = false;

uint8_t colonT[] = { 1, 0, 0, 0, 0, 0, 0 }; // colonT

uint8_t PREF_h_m_s_on_1[] = { 10 , 0 , 0 };
uint8_t PREF_h_m_s_off_1[] = { 16 , 0 , 0 };

uint8_t PREF_h_m_s_on_2[] = { 18 , 0 , 0 };
uint8_t PREF_h_m_s_off_2[] = { 22 , 0 , 0 };

uint32_t lastTime = 0;
uint32_t lastTimeMain = 0;
uint32_t flash_interval = 200;
uint8_t tempo_display_time = 10; //any unit = 500 millis

// Generic output pins
MD_Parola parola = MD_Parola(MD_MAX72XX::FC16_HW, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

boolean PREF_rotate = 0;
int PREF_detection_time_out = 1;
boolean PREF_detection_on = true;

#if USE_PREFS
Preferences preferences;
#endif

T_TIME_KEMET.ino

Arduino
Main File
/*T-Time Ver 1.0 2020-03-01*/

#define DEBUG_TT 1
#define USE_WIFI  1
#define USE_WEB 1
#define USE_NTP  1
#define USE_PREFS  1
#define USE_KEMET 1

#include "Include.h"
#include "Define.h"

void setup(void)
{
  DEBUG_START

#if USE_PREFS
  use_prefs();
#endif

  initParola(PREF_rotate);

  delay(3000);

#if USE_WIFI
  use_wifi();
#endif

#if USE_WEB
  use_web();
#endif

#if USE_KEMET
  kemet_init();
#endif

  //Multicore
  xTaskCreatePinnedToCore(
    updateTask,   /* Function to implement the task */
    "updateTask", /* Name of the task */
    13000,      /* Stack size in words */
    NULL,       /* Task input parameter */
    1,          /* Priority of the task */
    &Task1,      /* Task handle. */
    taskCore0);  /* Core where the task should be executed*/

  DEBUG_PRINTLN("Task update created...");

}

void loop(void)
{
  LOOP();
}

feed.ino

Arduino
void connect(WiFiClient* client, String url,String host) {
  (*client).print(String("GET ") + url + " HTTP/1.1\r\n" +
                "Host: " + host + "\r\n");
  (*client).println();
  (*client).println();
}
void refresh_news() {
  refresh_news_now = 0;
}

void getNEWSData() //client function to send/receive GET request data.
{
  String result = "";
  WiFiClient client;
  const int httpPort = 80;
  if (!client.connect(servernameNEWS.c_str(), httpPort)) {
    return;
  }

  // This will send the request to the server
  connect(&client,urlNEWS,servernameNEWS); 
    
  unsigned long timeout = millis();
  while (client.available() == 0) {
    if (millis() - timeout > TIMEOUT_WEB) {
      client.stop();
      return;
    }
  }
  NEWS_news_salvate = 0;
  
  while (client.available() && NEWS_news_salvate < MAX_NEWS) {
    result = client.readStringUntil('\n');
    if (cercaData(trovato, result, "<title><%!%[CDATA%[([^%]]*)", ric)) {
      //news_title = String(trovato);
      NEWS_news[NEWS_news_salvate] = String(trovato);
      NEWS_news_salvate++;
    } else
    if (cercaData(trovato, result, "<description><%!%[CDATA%[([^%]]*)", ric)) {
      NEWS_news[NEWS_news_salvate - 1] = String(NEWS_news[NEWS_news_salvate - 1] + "  -  " + trovato);
      DEBUG_PRINTLN(NEWS_news[NEWS_news_salvate - 1]);
    }
  }

}

bool cercaData(char* buf, String testo, String regExp, char* cerca) {
  MatchState ms;
  if (testo.length() > MAX_LUNGH_RICERCA)
    strncpy(cerca, testo.c_str(), MAX_LUNGH_RICERCA);
  else
    strcpy(cerca, testo.c_str());

  //DEBUG_PRINTLN (cerca);
  ms.Target(cerca);
  char resultC = ms.Match(regExp.c_str());

  switch (resultC)
  {
    case REGEXP_MATCHED:
      DEBUG_PRINTLN ("-----");
      DEBUG_PRINT("Matched on: ");
      //matching offsets in ms.capture
      DEBUG_PRINTF1("Captures: %d\n",ms.level);
      for (int j = 0; j < ms.level; j++)
      {
        DEBUG_PRINTF1("Capture number: %d\n",j + 1);
        DEBUG_PRINTF1("Text: '%s'\n",ms.GetCapture (buf, j));
#if !DEBUG_TT
        ms.GetCapture (buf, j);
#endif
      }
      return true;
      break;
    case REGEXP_NOMATCH:
      //DEBUG_PRINTLN ("No match.");
      break;
    default:
      DEBUG_PRINTF1("Regexp error: %d\n",resultC);
      break;

  }  // end of switch
  return false;
}

bool contains(String s, String search) {
    int lgsearch = search.length();
    int max = s.length() - lgsearch;

    for (int i = 0; i <= max; i++) {
        if (s.substring(i,i+lgsearch) == search) return true; // or i
    }

    return false; //or -1
} 

kemet.ino

Arduino
#if USE_KEMET
unsigned long PyroRead = 0;
unsigned long IR_threshold = 198000;
unsigned long sensor_time_out = 5000;
unsigned long sensor_time_in = 0;

// IR_threshold is in microsec (usec), therefore 198msec threshold

int IR_sensed = 0;

uint32_t KEMET_LAST_DETECTION = 0;

void kemet_init() {
  pinMode(KEMET_PIN, INPUT);    // sets the digital pin 25 as input
}

int kemet_loop() {
  sensor_time_in = millis();
  PyroRead = 0; // Reset readings
  IR_sensed = 0;
  while ((IR_sensed < 2) && ((millis()-sensor_time_in) < sensor_time_out)) { //Break after 2 good triggers or timeout
    PyroRead = pulseIn(KEMET_PIN, HIGH); //Measure trigger point
    if (PyroRead > IR_threshold) { //Make sure trigger is over 198msec)
      IR_sensed++; //Mark as a good trigger
    }
  }
  if(IR_sensed == 2) {
    KEMET_LAST_DETECTION = millis();
    DEBUG_PRINTLN("KEMET DETECTED");
    return 1;
  }
  DEBUG_PRINTLN("KEMET EXPIRED");
  return 0; 
}
boolean kemet_time_out() {
  static bool temp = true;
  boolean val = (((millis()-KEMET_LAST_DETECTION) > PREF_detection_time_out * 60000) && PREF_detection_on);
  if(val!=temp) DEBUG_PRINTLN(val?"KEMET TIME OUT":"KEMET ACTIVE");
  temp = val;
  return val;
}
#endif

preferences.ino

Arduino
#if USE_PREFS
void use_prefs() {
  preferences.begin(APP_NAME.c_str(), false);

  PREF_h_m_s_on_1[0]=preferences.getInt("h_on_1",PREF_h_m_s_on_1[0]);
  PREF_h_m_s_on_1[1]=preferences.getInt("m_on_1",PREF_h_m_s_on_1[1]);
  PREF_h_m_s_on_1[2]=preferences.getInt("s_on_1",PREF_h_m_s_on_1[2]);
  PREF_h_m_s_off_1[0]=preferences.getInt("h_off_1",PREF_h_m_s_off_1[0]);
  PREF_h_m_s_off_1[1]=preferences.getInt("m_off_1",PREF_h_m_s_off_1[1]);
  PREF_h_m_s_off_1[2]=preferences.getInt("s_off_1",PREF_h_m_s_off_1[2]);

  PREF_h_m_s_on_2[0]=preferences.getInt("h_on_2",PREF_h_m_s_on_2[0]);
  PREF_h_m_s_on_2[1]=preferences.getInt("m_on_2",PREF_h_m_s_on_2[1]);
  PREF_h_m_s_on_2[2]=preferences.getInt("s_on_2",PREF_h_m_s_on_2[2]);
  PREF_h_m_s_off_2[0]=preferences.getInt("h_off_2",PREF_h_m_s_off_2[0]);
  PREF_h_m_s_off_2[1]=preferences.getInt("m_off_2",PREF_h_m_s_off_2[1]);
  PREF_h_m_s_off_2[2]=preferences.getInt("s_off_2",PREF_h_m_s_off_2[2]);

  PREF_refresh_news_in_minutes=preferences.getUChar("refresh_news_in_minutes",PREF_refresh_news_in_minutes);
  
  PREF_rotate=preferences.getBool("ROTATE",PREF_rotate);

  PREF_detection_on=preferences.getBool("DETECTION",PREF_detection_on);  
  PREF_detection_time_out=preferences.getInt("DETECTION_TIME_OUT",PREF_detection_time_out);
}


void writePreferences() {

  preferences.putInt("h_on_1",PREF_h_m_s_on_1[0]);
  preferences.putInt("m_on_1",PREF_h_m_s_on_1[1]);
  preferences.putInt("s_on_1",PREF_h_m_s_on_1[2]);
  preferences.putInt("h_off_1",PREF_h_m_s_off_1[0]);
  preferences.putInt("m_off_1",PREF_h_m_s_off_1[1]);
  preferences.putInt("s_off_1",PREF_h_m_s_off_1[2]);

  preferences.putInt("h_on_2",PREF_h_m_s_on_2[0]);
  preferences.putInt("m_on_2",PREF_h_m_s_on_2[1]);
  preferences.putInt("s_on_2",PREF_h_m_s_on_2[2]);
  preferences.putInt("h_off_2",PREF_h_m_s_off_2[0]);
  preferences.putInt("m_off_2",PREF_h_m_s_off_2[1]);
  preferences.putInt("s_off_2",PREF_h_m_s_off_2[2]);

  preferences.putUChar("refresh_news_in_minutes",PREF_refresh_news_in_minutes);

  preferences.putBool("ROTATE",PREF_rotate);
  
  preferences.putBool("DETECTION",PREF_detection_on);
  preferences.putInt("DETECTION_TIME_OUT",PREF_detection_time_out);
  
}

void clearPreferences() {
  preferences.clear();
}
#endif

void save(char* name,int value) {
  #if USE_PREFS
  preferences.putInt(name,value);
  #endif
}
void save(char* name,String value) {
  #if USE_PREFS
  preferences.putString(name,value);
  #endif
}
void save(char* name,boolean value) {
  #if USE_PREFS
  preferences.putBool(name,value);
  #endif
}

serial.ino

Arduino
void readCommand()
{
  //Read command from the Arduino serial monitor to set the RTC.
  //Case-sensitive and must be entered exactly as (24-hour clock):
  //  Set yyyy-mm-dd hh:mm:ss

  //    char cmd[255]="set time yyyy-mm-dd hh:mm:ss";
  int i;

  if (Serial.available() > 0) {           //aNEWShing there?
    i = 0;                              //yes, read the available characters
    while (Serial.available() > 0) {
      cmd[i++] = char(Serial.read());
    }
    cmd[i] = 0x00;    //put in string terminator
    int off = 9;

    if (strncmp(cmd, "set time ", off) == 0) {
      set_time(cmd, off);
    } else if (strncmp(cmd, "set message ", 12) == 0) {
      set_message(cmd, 12);
    }
  }
}

stringmanipulation.ino

Arduino
char *mon2str(uint8_t mon, char *psz, uint8_t len)
// Get a label from PROGMEM into a char array
{
  static const __FlashStringHelper*  str[] =
  {
    F("Jan"), F("Feb"), F("Mar"), F("Apr"),
    F("May"), F("Jun"), F("Jul"), F("Aug"),
    F("Sep"), F("Oct"), F("Nov"), F("Dec")
  };

  strncpy_P(psz, (const prog_char *)str[mon], len);
  psz[len] = '\0';

  return (psz);
}

char *dow2str(uint8_t code, char *psz, uint8_t len)
{
  static const __FlashStringHelper* str[] =
  {
    F("Sun "), F("Mon "), F("Tue "),
    F("Wed "), F("Thu "), F("Fri "),
    F("Sat ")
  };

  strncpy_P(psz, (const prog_char *)str[code], len);
  psz[len] = '\0';

  return (psz);
}

void getTime(char *psz, boolean f)
// Code for reading clock time
{
  String st = (f ? printTimeFormated("%H:%M") : printTimeFormated("%H^%M"));
  sprintf(psz, "%s", st );
}
void getTime(char *psz)
// Code for reading clock time
{
  getTime(psz, true);
}
void getDate(char *psz)
// Code for reading clock date
{
  char  szBuf[10];
  struct tm time_tm = getTime_tm();
  sprintf(psz, "%d %s %s", time_tm.tm_mday, mon2str(time_tm.tm_mon, szBuf, sizeof(szBuf) - 1), printTimeFormated("%Y"));
}

void getWday(char *psz)
// Code for reading clock date
{
  struct tm time_tm = getTime_tm();
  dow2str(time_tm.tm_wday, psz, MAX_MESG);
}

String web_clean(String from_web) {
  from_web.replace("&#039;","'");
  from_web.replace("&amp;","&");
  from_web.replace("&aacute;","á");
  from_web.replace("&agrave;","à");
  from_web.replace("&Egrave;","E'");
  from_web.replace("&eacute;","é");
  from_web.replace("&egrave;","è");
  from_web.replace("&iacute;","í");
  from_web.replace("&igrave;","ì");
  from_web.replace("&oacute;","ó");
  from_web.replace("&ograve;","ò");
  from_web.replace("&uacute;","ú");
  from_web.replace("&ugrave;","ù");
  from_web.replace("&rsquo;","'");//’
  from_web.replace("&lsquo;","'");//‘
  from_web.replace("&quot;","\"");
  from_web.replace("&ldquot;","\"");//“
  from_web.replace("&rdquot;","\"");//”
  from_web.replace("&ldquo;","\"");//”
  from_web.replace("&rdquo;","\"");//”
  return String(from_web);
}

void getTimer(char *psz, boolean f)
// Code for reading clock time
{
  String st = (f ? printTimerFormated("%02d:%02d.%02d") : printTimerFormated("%02d^%02d.%02d"));
  sprintf(psz, "%s", st );
}

my_time.ino

Arduino
#if USE_NTP
#include <sys/time.h>
const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 3600;
const int   daylightOffset_sec = 3600;
void ntp() {
  const char* ntpServer = "pool.ntp.org";
  const long  gmtOffset_sec = 3600;
  const int   daylightOffset_sec = 3600;
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  printLocalTime();
}

void printLocalTime()
{
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    DEBUG_PRINTLN("Failed to obtain time");
    return;
  }
  DEBUG_PRINTLN2(&timeinfo, "%A, %B %d %Y %H:%M:%S");
}
#endif
String printTimeFormated(String format)
{
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo))
  {
    DEBUG_PRINTLN("Failed to obtain time");
   return "00:00";
  }
  char timeStringBuff[50]; //50 chars should be enough
  strftime(timeStringBuff, sizeof(timeStringBuff), format.c_str() , &timeinfo);
  //"%A, %B %d %Y %H:%M:%S"
  return String(timeStringBuff);
}
long getTimeSeconds()
{
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo))
  {
    DEBUG_PRINTLN("Failed to obtain time");
   return 0;
  }
  return timeinfo.tm_sec+timeinfo.tm_min*60L+timeinfo.tm_hour*3600L;
}
struct tm getTime_tm()
{
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo))
  {
    DEBUG_PRINTLN("Failed to obtain time");
    return timeinfo;
  }
  return timeinfo;
}

String printTimerFormated(String format)
{
  uint32_t elasped = millis()/1000 - timer[0];
  if (elasped > timer[1]) return String("00:00.00");
  uint32_t remaining = timer[1] - elasped;
  char timeStringBuff[10]; //50 chars should be enough
  
  sprintf(timeStringBuff, format.c_str(), remaining/3600, (remaining/60)%60, remaining%60);
  return String(timeStringBuff);
}

boolean timer_fired() {
  if (!check_timer_on() && timer_on)  {
    timer_on = false;
    return true;
  }
  return false;
}
boolean check_timer_on() {
  uint32_t elasped = millis()/1000 - timer[0];
  if (elasped < timer[1])  {
    timer_on = true;
    return true;
  }
  return false;
}

boolean display_off() {
  long time_now = getTimeSeconds();
  long time_on_1 = PREF_h_m_s_on_1[0] * 3600 + PREF_h_m_s_on_1[1] * 60 + PREF_h_m_s_on_1[2];
  long time_off_1 = PREF_h_m_s_off_1[0] * 3600 + PREF_h_m_s_off_1[1] * 60 + PREF_h_m_s_off_1[2];
  long time_on_2 = PREF_h_m_s_on_2[0] * 3600 + PREF_h_m_s_on_2[1] * 60 + PREF_h_m_s_on_2[2];
  long time_off_2 = PREF_h_m_s_off_2[0] * 3600 + PREF_h_m_s_off_2[1] * 60 + PREF_h_m_s_off_2[2];
  return !((time_now > time_on_1 && time_now < time_off_1) || (time_now > time_on_2 && time_now < time_off_2));
}

weather.ino

Arduino
/*WETHER*/

#include <ArduinoJson.h>    //https://github.com/bblanchon/ArduinoJson

void getWeatherData() //client function to send/receive GET request data.
{
  String result = "";
  WiFiClient client;
  const int httpPort = 80;
  if (!client.connect(servername, httpPort)) {
    return;
  }
  // We now create a URI for the request
  String url = "/data/2.5/forecast?q=" + String(City[CityInd]) + "&lang=" + lang + "&units=metric&cnt=5&APPID=" + APIKEY;

  // This will send the request to the server
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + servername + "\r\n" +
               "Connection: close\r\n\r\n");
  unsigned long timeout = millis();
  while (client.available() == 0) {
    if (millis() - timeout > TIMEOUT_WEB) {
      client.stop();
      return;
    }
  }

  // Read all the lines of the reply from server
  while (client.available()) {
    result = client.readStringUntil('\r');
  }

  char jsonArray [result.length() + 1];
  result.toCharArray(jsonArray, sizeof(jsonArray));
  jsonArray[result.length() + 1] = '\0';
  /*
  StaticJsonBuffer<4096> json_buf;
  JsonObject &root = json_buf.parseObject(jsonArray);*/
  

      DEBUG_PRINTLN(jsonArray);
  
  StaticJsonDocument<4096> doc;
    // Deserialize the JSON document
  DeserializationError error = deserializeJson(doc, jsonArray);

  // Test if parsing succeeds.
  if (error) {
    Serial.print("deserializeJson() failed: ");
    DEBUG_PRINTLN(error.c_str());
    return;
  }
  
  // Get the root object in the document
  JsonObject root = doc.as<JsonObject>();
  
  if (root.isNull())
  {
    DEBUG_PRINTLN("parseObject() failed");
  }

  String location = root["city"]["name"];
  String t0 = root["list"][1]["main"]["temp"];
  String t2 = root["list"][2]["main"]["temp"];
  String t4 = root["list"][4]["main"]["temp"];
  String temperature = "+3h: "+ t0 + "@  +6h: " + t2 + "@  +12h: " + t4 + "@  ";
  String weather = root["list"][0]["weather"]["main"];
  String d0 = root["list"][1]["weather"][0]["description"];
  String d4 = root["list"][4]["weather"][0]["description"];
  String description = "+3h: " + d0 + "  +12h: " + d4;
  String idString = root["list"][0]["weather"][0]["id"];
  String timeS = root["list"][0]["dt_txt"];

  //DEBUG_PRINTLN(location + " - " + temperature + " - " + weather + " - " + description + " - " + timeS);
  meteo = "" + location + " " + temperature +  " - " +  description;

  DEBUG_PRINTLN(meteo);
}
/*WETHER*/

web.ino

Arduino
#if USE_WEB
void use_web(){
  DEBUG_PRINTLN("Starting server");
  server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
    //request->send(200, "text/plain", "Hello World");
    web(request);
  });

  server.begin();
}

void style(AsyncResponseStream *response) {
  response->print("<style>");
  response->print("  .heading {");
  response->print("  position: static;");
  response->print("  display: block;");
  response->print("  margin-right: 1px;");
  response->print("  margin-left: 1px;");
  response->print("  float: none;");
  response->print("  text-align: center;");
  response->print("}");
  response->print(".button {");
  //response->print("  display: inline;");
  //response->print("  float: right;");
  response->print("  border: 1px solid #000;");
  response->print("  border-radius: 10px;");
  response->print("  background-color: #4CAF50;"); /* Green */
  response->print("  border: none;");
  response->print("  color: white;");
  response->print("  padding: 15px 32px;");
  response->print("  text-align: center;");
  response->print("  text-decoration: none;");
  response->print("  font-size: 16px;");
  response->print("}");
  response->print(".text-block {");
  response->print("  -moz-appearance: textfield;");
  response->print("  -webkit-appearance: textfield;");
  response->print("  position: relative;");
  response->print("  display: block;");
  response->print("  overflow: visible;");
  response->print("  min-height: 40px;");
  response->print("  min-width: 150px;");
  response->print("  clear: both;");
  response->print("  border: 5px solid #1b0e81;");
  response->print("  border-radius: 10px;");
  response->print("  background-image: -webkit-linear-gradient(219deg, #71b4fd, #fff);");
  response->print("  background-image: linear-gradient(231deg, #71b4fd, #fff);");
  response->print("  box-shadow: 0 0 6px 0 #fff;");
  response->print("  font-weight: 700;");
  response->print("  letter-spacing: 0px;");
  response->print("  text-transform: none;");
  response->print("}");
  response->print(".text-block2 {");
  response->print("  position: relative;");
  response->print("  display: block;");
  response->print("  overflow: visible;");
  response->print("  min-height: 40px;");
  response->print("  min-width: 150px;");
  response->print("  clear: both;");
  response->print("  border: 5px solid #1b0e81;");
  response->print("  border-radius: 10px;");
  response->print("  background-image: -webkit-linear-gradient(219deg, #31a1fd, #fff);");
  response->print("  background-image: linear-gradient(231deg, #31a1fd, #fff);");
  response->print("  box-shadow: 0 0 6px 0 #fff;");
  response->print("  font-weight: 700;");
  response->print("  letter-spacing: 0px;");
  response->print("  text-transform: none;");
  response->print("}");
  response->print(".body {");
  response->print("  border: 10 px solid #000;");
  response->print("  background-color: #000;");
  response->print("}");
  response->print(".section {");
  response->print("  max-height: 30px;");
  response->print("  min-height: 30px;");
  response->print("  border-style: none;");
  response->print("  opacity: 0;");
  response->print("  -webkit-perspective: 751px;");
  response->print("}");
  response->print("</style>");
}

void web(AsyncWebServerRequest *request) {
  int params = request->params();
  for (int i = 0; i < params; i++) {
    AsyncWebParameter* p = request->getParam(i);
    {
      DEBUG_PRINTLN("GET[" + p->name() + "]: " + p->value());
      if (strncmp(p->name().c_str(), "time", 4) == 0) {
        set_time(p->value().c_str(), 0);
      } else if (strncmp(p->name().c_str(), "message", 7) == 0) {
        set_message(p->value().c_str(), 0); 
      } else if (strncmp(p->name().c_str(), "rotate", 6) == 0) {
        PREF_rotate = !PREF_rotate;
        save("ROTATE",PREF_rotate);
        setOrientation(PREF_rotate);
      } else if (strncmp(p->name().c_str(), "icon", 4) == 0) {
        set_icon(p->value().c_str(), 0);
      } else if (strncmp(p->name().c_str(), "uicon", 5) == 0) {
        unset_icon();
      } else if (strncmp(p->name().c_str(), "intensity", 9) == 0) {
        set_intensity(p->value().c_str(), 0);
      } else if (strncmp(p->name().c_str(), "reset", 5) == 0) {
        reset();
      } else if (strncmp(p->name().c_str(), "speed", 5) == 0) {
        set_speed(p->value().c_str(), 0);
      } else if (strncmp(p->name().c_str(), "invert", 6) == 0) {
        invert();
      } else if (strncmp(p->name().c_str(), "ntp", 3) == 0) {
      #if USE_NTP
        ntp();
      #endif
      } else if (strncmp(p->name().c_str(), "wifi", 4) == 0) {
        set_wifi(p->value().c_str(), 0);
      } else if (strncmp(p->name().c_str(), "on", 2) == 0) {
        on();
      } else if (strncmp(p->name().c_str(), "det_time_out", 12) == 0) {
        //setDetTimeOut(p->value().c_str(), 0);
          PREF_detection_time_out = atoi(p->value().c_str());
          save("DETECTION",PREF_detection_time_out);
      } else if (strncmp(p->name().c_str(), "detection_on", 12) == 0) {
        PREF_detection_on = true;
        save("DETECTION",PREF_detection_on);
      } else if (strncmp(p->name().c_str(), "detection_off", 13) == 0) {
        PREF_detection_on = false;
        save("DETECTION",PREF_detection_on);
      } else if (strncmp(p->name().c_str(), "off", 3) == 0) {
        off();
      } else if (strncmp(p->name().c_str(), "disreset", 8) == 0) {
        display_reset();
      } else if (strncmp(p->name().c_str(), "displayon_1", 11) == 0) {
        displayon_1(p->value().c_str(), 0);
      } else if (strncmp(p->name().c_str(), "displayoff_1", 12) == 0) {
        displayoff_1(p->value().c_str(), 0);
      } else if (strncmp(p->name().c_str(), "displayon_2", 11) == 0) {
        displayon_2(p->value().c_str(), 0);
      } else if (strncmp(p->name().c_str(), "displayoff_2", 12) == 0) {
        displayoff_2(p->value().c_str(), 0);
      } else if (strncmp(p->name().c_str(), "allert", 6) == 0) {
        set_allert(p->value().c_str(), 0);
      } else if (strncmp(p->name().c_str(), "uallert", 7) == 0) {
        unset_allert();
      } else if (strncmp(p->name().c_str(), "autostdbyon", 11) == 0) {
        active_autostdby();
      } else if (strncmp(p->name().c_str(), "autostdbyoff", 12) == 0) {
        deactive_autostdby();
      } else if (strncmp(p->name().c_str(), "refresh_news", 12) == 0) {
        refresh_news();
      }  else if (strncmp(p->name().c_str(), "set_timer", 9) == 0) {
        set_timer(p->value().c_str(), 0);
      } 
    }
  }
  AsyncResponseStream *response = request->beginResponseStream("text/html");
  response->addHeader("Server", "ESP Async Web Server");
  response->printf("<!DOCTYPE html><html><head><title>Webpage at %s</title>", request->url().c_str());
  style(response);
  response->printf("</head><body>");
  char z[2];
  itoa(intensity , z , 0);
  String str = String(z);
  response->print("<h1 class=\"heading\">" +APP_NAME+" "+ APP_VERSION + "</h1>");
  response->print("<h1 class=\"heading\">ESP32 MAX7219 KEMET-SS-430</h1>");
  response->print("<div class=\"section\"></div>");
  response->print("<div class=\"text-block2\"  id=\"demo\"></div>");
  response->print("<div class=\"section\"></div>");
  response->printf("<div contenteditable=\"true\" class=\"text-block\" type=\"text\" id=\"intensity\">%d</div>", intensity);
  response->print("<div class=\"button\" onclick=\"setIntensity();\">SET INTENSITY</div>");
  response->print("<div class=\"section\"></div>");
  response->print("<div contenteditable=\"true\" class=\"text-block\" type=\"text\" id=\"message\">" + message + "</div>");
  response->print("<div class=\"button\" onclick=\"setMessage();\">SET MESSAGE</div>");
  response->print("<div class=\"section\"></div>");
  response->print("<div contenteditable=\"true\" class=\"text-block\" type=\"text\" id=\"allert\">" + allert + "</div>");
  response->print("<div class=\"button\" onclick=\"setAllert();\">SET ALLERT</div>");
  response->print("<div class=\"button\" onclick=\"unsetAllert();\">UNSET ALLERT</div>");
  response->print("<div class=\"section\"></div>");
  response->printf("<div contenteditable=\"true\" class=\"text-block\" type=\"text\" id=\"speed\">%02d</div>", speed);
  response->print("<div class=\"button\"  onclick=\"setSpeed();\">SET SPEED</div>");
  response->print("<div class=\"section\"></div>");
  response->printf("<div contenteditable=\"true\" class=\"text-block\" type=\"text\" id=\"timer\">%02d:%02d.%02d</div>", timer[1]/3600, (timer[1]/60)%60, timer[1]%60);
  response->print("<div class=\"button\" onclick=\"set_timer();\">SET TIMER</div>");
  response->print("<div class=\"section\"></div>");
  response->print("<div class=\"text-block\" type=\"text\" id=\"time\"></div>");
  response->print("<div class=\"button\" onclick=\"setTime();\">SET TIME</div>");
  response->print("<div class=\"section\"></div>");
  response->printf("<div contenteditable=\"true\" class=\"text-block\" type=\"text\" id=\"displayon_1\">%02d:%02d:%02d</div>", PREF_h_m_s_on_1[0], PREF_h_m_s_on_1[1], PREF_h_m_s_on_1[2]);
  response->printf("<div contenteditable=\"true\" class=\"text-block\" type=\"text\" id=\"displayoff_1\">%02d:%02d:%02d</div>", PREF_h_m_s_off_1[0], PREF_h_m_s_off_1[1], PREF_h_m_s_off_1[2]);
  response->printf("<div contenteditable=\"true\" class=\"text-block\" type=\"text\" id=\"displayon_2\">%02d:%02d:%02d</div>", PREF_h_m_s_on_2[0], PREF_h_m_s_on_2[1], PREF_h_m_s_on_2[2]);
  response->printf("<div contenteditable=\"true\" class=\"text-block\" type=\"text\" id=\"displayoff_2\">%02d:%02d:%02d</div>", PREF_h_m_s_off_2[0], PREF_h_m_s_off_2[1], PREF_h_m_s_off_2[2]);
  response->print("<div class=\"button\" onclick=\"setOnOff();\">SAVE DISPLAY ON OFF</div>");
  response->print("<div class=\"button\" onclick=\"autostdbyOn();\" id=\"autostdbyon\">ACTIVATE</div>");
  response->print("<div class=\"button\" onclick=\"autostdbyOff();\" id=\"autostdbyoff\">DEACTIVATE</div>");
  response->print("<div class=\"section\"></div>");
  response->print("<div class=\"button\" type=\"button\" onclick=\"inverti();\">INVERTI</div>");
  response->print("<div class=\"button\" type=\"button\" onclick=\"rotate();\">ROTATE</div>");
  response->print("<div class=\"section\"></div>");
  response->print("<div class=\"button\" type=\"button\" onclick=\"reset();\">RESET</div>");
  response->print("<div class=\"section\"></div>");
  response->print("<div class=\"button\" type=\"button\" onclick=\"ntp();\">FORECE NTP</div>");
  response->print("<div class=\"section\"></div>");
  response->printf("<div contenteditable=\"true\" class=\"text-block\" type=\"text\" id=\"det_time_out\">%02d</div>", PREF_detection_time_out);
  response->print("<div class=\"button\" onclick=\"setDetTimeOut();\">SAVE Detection Time Out</div>");
  response->print("<div class=\"button\" type=\"button\" onclick=\"detection_on();\">DETECTION ON</div>");
  response->print("<div class=\"button\" type=\"button\" onclick=\"detection_off();\">DETECTIONOFF</div>");
  response->print("<div class=\"section\"></div>");
  response->print("<div class=\"button\" type=\"button\" onclick=\"on();\">ON</div>");
  response->print("<div class=\"button\" type=\"button\" onclick=\"off();\">OFF</div>");
  response->print("<div class=\"button\" type=\"button\" onclick=\"disReset();\">DISPLEY RESET</div>");
  response->print("<div class=\"section\"></div>");
  response->print("<div class=\"button\" type=\"button\" onclick=\"refresh_news();\">REFRESH NEWS</div>");
  response->print("<div class=\"section\"></div>");
  for (int sc = 0; sc < NEWS_news_salvate; sc++) {
    response->printf("<div class=\"text-block\" type=\"text\" id=\"news%02d\">News %02d - ", sc, sc);
    response->print(NEWS_news[sc] + "</div>");
  }
  response->print("<div class=\"section\"></div>");
  response->print("<div class=\"section\"></div>");

  response->print("<script>(function () {");
  response->print("function checkTime(i) { ");
  response->print(" return (i < 10) ? \"0\" + i : i;}");
  response->print("function startTime() {");
  response->print("var today = new Date(); var dd = today.getDate(); var mm = today.getMonth()+1; var yyyy = today.getFullYear();");
  response->print("if(dd<10){dd='0'+dd} if(mm<10){mm='0'+mm}");
  response->print("var h = checkTime(today.getHours()),m = checkTime(today.getMinutes()),s = checkTime(today.getSeconds());");
  //response->print("if(h<10){h='0'+h} if(m<10){m='0'+m} if(s<10){s='0'+s} ");
  response->print("document.getElementById('time').innerHTML = yyyy+'-'+mm+'-'+dd + \"-\" + h + \":\" + m + \":\" + s;");
  response->print("t = setTimeout(function () {startTime()}, 500);");
  response->print("}startTime();");
  response->print("})();");
  response->print("function setTime() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?time=\"+document.getElementById('time').innerHTML");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?time=\"+document.getElementById('time').innerHTML, true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function setMessage() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?message=\"+encodeURI(document.getElementById('message').innerHTML)");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?message=\"+encodeURI(document.getElementById('message').innerHTML), true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function setAllert() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?allert=\"+encodeURI(document.getElementById('allert').innerHTML)");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?allert=\"+encodeURI(document.getElementById('allert').innerHTML), true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function unsetAllert() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?uallert\"");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?uallert\", true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function setIntensity() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?intensity=\"+encodeURI(document.getElementById('intensity').innerHTML)");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?intensity=\"+encodeURI(document.getElementById('intensity').innerHTML), true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function setIcon() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?icon=\"+encodeURI(document.getElementById('icon').innerHTML)");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?icon=\"+encodeURI(document.getElementById('icon').innerHTML), true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function unsetIcon() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?uicon\"");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?uicon\", true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function setSpeed() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?speed=\"+encodeURI(document.getElementById('speed').innerHTML)");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?speed=\"+encodeURI(document.getElementById('speed').innerHTML), true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function setOnOff() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?displayon_1=\"+encodeURI(document.getElementById('displayon_1').innerHTML)+\"&displayoff_1=\"+encodeURI(document.getElementById('displayoff_1').innerHTML)+\"&displayon_2=\"+encodeURI(document.getElementById('displayon_2').innerHTML)+\"&displayoff_2=\"+encodeURI(document.getElementById('displayoff_2').innerHTML)");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?displayon_1=\"+encodeURI(document.getElementById('displayon_1').innerHTML)+\"&displayoff_1=\"+encodeURI(document.getElementById('displayoff_1').innerHTML)+\"&displayon_2=\"+encodeURI(document.getElementById('displayon_2').innerHTML)+\"&displayoff_2=\"+encodeURI(document.getElementById('displayoff_2').innerHTML), true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function autostdbyOn() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?autostdbyon\"");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?autostdbyon\", true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function autostdbyOff() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?autostdbyoff\"");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?autostdbyoff\", true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function inverti() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?invert\"");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?invert\", true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function rotate() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?rotate\"");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?rotate\", true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function reset() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?reset\"");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?reset\", true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function ntp() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?ntp\"");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?ntp\", true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function setDetTimeOut() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?det_time_out=\"+encodeURI(document.getElementById('det_time_out').innerHTML)");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?det_time_out=\"+encodeURI(document.getElementById('det_time_out').innerHTML), true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function detection_on() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?detection_on\"");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?detection_on\", true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function detection_off() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?detection_off\"");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?detection_off\", true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function on() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?on\"");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?on\", true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function off() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?off\"");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?off\", true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function disReset() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?disreset\"");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?disreset\", true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function refresh_news() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?refresh_news\"");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?refresh_news\", true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("function set_timer() {");
  response->print("  var xhttp = new XMLHttpRequest();");
  response->print("  xhttp.onreadystatechange = function() {");
  response->print("    if (this.readyState == 4 && this.status == 200) {");
  response->print("      document.getElementById(\"demo\").innerHTML = \"/?set_timer=\"+document.getElementById('timer').innerHTML");
  response->print("    }");
  response->print("  };");
  response->print("  xhttp.open(\"GET\", \"/?set_timer=\"+document.getElementById('timer').innerHTML, true);");
  response->print("  xhttp.send();");
  response->print("}");
  response->print("</script>");
  response->print("</body></html>");
  //send the response last
  request->send(response);
}

#endif

wifi.ino

Arduino
#if USE_WIFI

void setupMDNS() {
  char host[16];
  snprintf(host, 16, "ESP%012llX", ESP.getEfuseMac());
  MDNS.begin(host);
  MDNS.addService("http", "tcp", 80);
  DEBUG_PRINTF1("Ready! Open http://%s.local in your browser\n", host);
}

void use_wifi() {
  DEBUG_PRINTLN("Starting WIFI");
  // delete old config
  WiFi.disconnect(true);
  delay(1000);
  // Examples of different ways to register wifi events
  WiFi.onEvent(WiFiEvent);
  // Remove WiFi event
  // Serial.print("WiFi Event ID: ");
  // DEBUG_PRINTLN(eventID);
  // WiFi.removeEvent(eventID);
  
  WiFi.begin (WIFIs[0].c_str(), WIFIs[1].c_str());
}

void WiFiEvent (WiFiEvent_t event)
{
    DEBUG_PRINTF1("[WiFi-event] event: %d\n", event);
    switch (event) {
        case SYSTEM_EVENT_WIFI_READY: 
            DEBUG_PRINTLN("WiFi interface ready");
            break;
        case SYSTEM_EVENT_SCAN_DONE:
            DEBUG_PRINTLN("Completed scan for access points");
            break;
        case SYSTEM_EVENT_STA_START:
            DEBUG_PRINTLN("WiFi client started");
            break;
        case SYSTEM_EVENT_STA_STOP:
            DEBUG_PRINTLN("WiFi clients stopped");
            break;
        case SYSTEM_EVENT_STA_CONNECTED:
            DEBUG_PRINTLN("Connected to access point");
            break;
        case SYSTEM_EVENT_STA_DISCONNECTED:
            DEBUG_PRINTLN("Disconnected from WiFi access point");
            WiFi.begin (WIFIs[wifi*2].c_str(), WIFIs[wifi*2+1].c_str());
            wifi=(wifi+1)%(sizeof(WIFIs)/2);
            break;
        case SYSTEM_EVENT_STA_AUTHMODE_CHANGE:
            DEBUG_PRINTLN("Authentication mode of access point has changed");
            break;
        case SYSTEM_EVENT_STA_GOT_IP:
            DEBUG_PRINT("Obtained IP address: ");
            ip = String(WiFi.localIP());
            displayIP = true;
            #if USE_NTP
              DEBUG_PRINTLN("Start NTP");
              ntp();
            #endif
            setupMDNS();
            break;
        case SYSTEM_EVENT_STA_LOST_IP:
            DEBUG_PRINTLN("Lost IP address and IP address is reset to 0");
            break;
        case SYSTEM_EVENT_STA_WPS_ER_SUCCESS:
            DEBUG_PRINTLN("WiFi Protected Setup (WPS): succeeded in enrollee mode");
            break;
        case SYSTEM_EVENT_STA_WPS_ER_FAILED:
            DEBUG_PRINTLN("WiFi Protected Setup (WPS): failed in enrollee mode");
            break;
        case SYSTEM_EVENT_STA_WPS_ER_TIMEOUT:
            DEBUG_PRINTLN("WiFi Protected Setup (WPS): timeout in enrollee mode");
            break;
        case SYSTEM_EVENT_STA_WPS_ER_PIN:
            DEBUG_PRINTLN("WiFi Protected Setup (WPS): pin code in enrollee mode");
            break;
        case SYSTEM_EVENT_AP_START:
            DEBUG_PRINTLN("WiFi access point started");
            break;
        case SYSTEM_EVENT_AP_STOP:
            DEBUG_PRINTLN("WiFi access point  stopped");
            break;
        case SYSTEM_EVENT_AP_STACONNECTED:
            DEBUG_PRINTLN("Client connected");
            break;
        case SYSTEM_EVENT_AP_STADISCONNECTED:
            DEBUG_PRINTLN("Client disconnected");
            break;
        case SYSTEM_EVENT_AP_STAIPASSIGNED:
            DEBUG_PRINTLN("Assigned IP address to client");
            break;
        case SYSTEM_EVENT_AP_PROBEREQRECVED:
            DEBUG_PRINTLN("Received probe request");
            break;
        case SYSTEM_EVENT_GOT_IP6:
            DEBUG_PRINTLN("IPv6 is preferred");
            break;
        case SYSTEM_EVENT_ETH_START:
            DEBUG_PRINTLN("Ethernet started");
            break;
        case SYSTEM_EVENT_ETH_STOP:
            DEBUG_PRINTLN("Ethernet stopped");
            break;
        case SYSTEM_EVENT_ETH_CONNECTED:
            DEBUG_PRINTLN("Ethernet connected");
            break;
        case SYSTEM_EVENT_ETH_DISCONNECTED:
            DEBUG_PRINTLN("Ethernet disconnected");
            break;
        case SYSTEM_EVENT_ETH_GOT_IP:
            DEBUG_PRINTLN("Obtained IP address");
            break;
        default: break;
    }
}
#endif

main_loop.ino

Arduino
Main Loop
void LOOP() {
  
  if(timer_fired()) set_allert("TIMER FIRED");
  if((autostdbyActivate && !kemet_time_out() && !display_off()) || allertOn) { 
    on();
  }

  if (parola.displayAnimate())
  {
    if (!allertOn || STATO_SCORRI_ALLERT > allertDuration)
    {
      if (millis() - lastTimeMain >= 180000) //ogni tre minuti
      {
        lastTimeMain = millis();

        if (STATO_GET_DISPLAY_ON) {
          display_reset();
        }
      }
      if (parola.getZoneStatus(0))
      {
        if (autostdbyActivate && kemet_time_out()) {
          off();
          delay(1000);
        } 
        MainSceneNext();
        parola.displayReset(0);
      }
    }
    //PACMAN
    if ((STATO_SCENA_LOOP_1 != 0) && (millis() - lastTime >= flash_interval))
    {
      lastTime = millis();
      if (!allertOn || STATO_SCORRI_ALLERT > allertDuration) {
        PacManNext();
        parola.displayReset(1);
      } else {
        if (parola.getZoneStatus(0)) {
          parola.setIntensity(10);
          parola.displayClear();
          AllertNext();
          parola.displayReset(2);
          STATO_SCORRI_ALLERT++;
          if (STATO_SCORRI_ALLERT > allertDuration) {
            parola.setIntensity(intensity);
            flash_interval = 200;
          } else {
            flash_interval = 500;
          }
        }
      }
    }
  }
}

secene.ino

Arduino
Scenes selection
void MainSceneNext() {
  switch (STATO_SCENA_LOOP_1)
  {
    case 0:
      if (STATO_GET_DISPLAY_ON) {
        display_reset(); //per pulire lo schermo
      } 
      //delay(3000);
      parola.setTextEffect(0, pa_scroll_up(), pa_scroll_left());
      STATO_SCENA_LOOP_1++;
      SecondaryDisplay();
      break;
    case 1:
      if (!animazioneTime(pa_scroll_up() , pa_scroll_left() , 5))
        STATO_SCENA_LOOP_1++;
      break;
    case 2:
      //delay(3000);
      parola.setTextEffect(0, pa_scroll_left(), pa_scroll_left());
      if (NEWS_news_salvate > 0) {
        strcpy(szMesg, NEWS_news[NEWS_news_scorri].c_str());
        NEWS_news_scorri = (NEWS_news_scorri + 1) % NEWS_news_salvate;
      }
      STATO_SCENA_LOOP_1++;
      break;
    case 3: // day of week
      parola.setTextEffect(0, pa_scroll_left(), PA_NO_EFFECT);
      STATO_SCENA_LOOP_1++;
      getWday(szMesg);
      break;
    case 4: // Calendar
      parola.setTextEffect(0, pa_scroll_left(), pa_scroll_left());
      STATO_SCENA_LOOP_1++;
      getDate(szMesg);
      break;
    case 5: // Meteo
      parola.setTextEffect(0, pa_scroll_left(), pa_scroll_left());
      STATO_SCENA_LOOP_1++;
      strcpy(szMesg, meteo.c_str());
      break;
    case 6: // Animation
      parola.setTextEffect(0, PA_PRINT, PA_NO_EFFECT);
      if (!animazione())
        STATO_SCENA_LOOP_1++;
      break;
    case 7: // animazioneTime
      parola.setTextEffect(0, PA_PRINT, PA_NO_EFFECT);
      if (!animazioneTimer(pa_scroll_up(), pa_scroll_left() , 10))
        STATO_SCENA_LOOP_1++;
      break;
    default:  
      STATO_SCENA_LOOP_1 = 0;
      break;
  }
}

void SecondaryDisplay() {
       switch (STATO_SCENA_LOOP_2) {
        case 0:
          if (displayIP) {
            strcpy(szMesg, ip.c_str());
            displayIP = false;
          }
          strcpy(szMesg, message.c_str());
          break;
        case 1:
          strcpy(szMesg, "VACANCY");
          break;
        case 2:
          strcpy(szMesg, "NO VACANCY");
          break;
        case 3:
          strcpy(szMesg, "NO VACANCY");
          break;
        case 4:
          strcpy(szMesg, "NO VACANCY");
          break;
        default:
          strcpy(szMesg, message.c_str());
          break;
      }
}

void PacManNext() {
   switch (STATO_SCORRI_PACMAN) {
          case -2:
            sprintf(szSolo, " ");
            STATO_SCORRI_PACMAN = -1;
            break;
          case -1:
            sprintf(szSolo, icon.c_str());
            STATO_SCORRI_PACMAN = -2;
            break;
          case 0:
            sprintf(szSolo, "%c", 201); //"&");
            STATO_SCORRI_PACMAN++;
            break;
          case 1:
            sprintf(szSolo, "%c", 202); //"$");
            STATO_SCORRI_PACMAN++;
            break;
          case 2:
            sprintf(szSolo, "%c", 203); //"#");
            STATO_SCORRI_PACMAN++;
            break;
          case 3:
            sprintf(szSolo, "%c", 204); //"#");
            STATO_SCORRI_PACMAN++;
            break;
          case 4:
            sprintf(szSolo, "%c", 203); //"#");
            STATO_SCORRI_PACMAN++;
            break;
          default: //4
            sprintf(szSolo, "%c", 202); //"$");
            STATO_SCORRI_PACMAN = 0;
            break;
        }
}
void PacManNext(int phase) {
            sprintf(szSolo, "%c", 201); //"&");
            STATO_SCORRI_PACMAN=1;
}
void AllertNext() {
  switch (STATO_SCORRI_ALLERT % 2) {
            case 0:
              sprintf(szMesg, allert.c_str());
              break;
            default: //1
              sprintf(szMesg, " ");
              break;
          }
}

task.ino

Arduino
Parallel task for weather/news update
void updateTask( void * pvParameters ) {
  DEBUG_PRINTLN("Task 2 Started");

  while (true) {
    //DEBUG_PRINTLN(taskMessage);
    //delay(500); //any 5 seconds
    if (((millis() - lastTimeNews) >= refresh_news_now) && WiFi.status() == WL_CONNECTED)
    {
      refresh_news_now = PREF_refresh_news_in_minutes * 60000; 
      lastTimeNews = millis();
      getWeatherData();
      DEBUG_PRINTLN("---->WEATHER");
      getNEWSData();
      DEBUG_PRINTLN("---->NEWS");
    }
    
    disableCore0WDT();
    kemet_loop();
    enableCore0WDT();
  }
}

Include.h

C/C++
Include the following libraries
// Header file includes
#include <Arduino.h>
#include <WiFi.h>
#include <ESPmDNS.h>
#include <MD_Parola.h>
#include "JF_Font_Data.h"
#include <Regexp.h>
#include <TimeLib.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#if USE_PREFS
#include <Preferences.h>
#endif

JF_Font_Data.h

C/C++
Font definitions
// Data file for user example user defined fonts
#ifndef FONTDATA_H
#define FONTDATA_H

uint8_t jF_Custom[] = {
	0,		// 0
	0,		// 1
	0,		// 2
	0,		// 3
	0,		// 4
	0,		// 5
	0,		// 6
	0,		// 7
	0,		// 8
	0,		// 9
	0,		// 10
	0,		// 11
	0,		// 12
	0,		// 13
	0,		// 14
	0,		// 15
	0,		// 16
	0,		// 17
	0,		// 18
	0,		// 19
	0,		// 20
	0,		// 21
	0,		// 22
	0,		// 23
	0,		// 24
	0,		// 25
	0,		// 26
	0,		// 27
	0,		// 28
	0,		// 29
	0,		// 30
	0,		// 31
	1, 0,		// 32 - 'Space'
	1, 95,						// 33 - '!'
	3, 7, 0, 7,					// 34 - '"'
	//5, 20, 127, 20, 127, 20,	// 35 - '#'
 8, 0, 56, 124, 254, 254, 234, 198, 68, 
	//5, 36, 42, 127, 42, 18,		// 36 - '$'
 8, 0, 56, 124, 254, 254, 250, 108, 40, 
	//5, 35, 19, 8, 100, 98,		// 37 - '%'
 8, 0, 56, 124, 254, 254, 250, 124, 40, 
	//5, 54, 73, 85, 34, 80,		// 38 - '&'
 8, 0, 56, 124, 254, 254, 250, 124, 56, 
	3, 8, 7, 3,					// 39 - '''
	3, 28, 34, 65,				// 40 - '('
	3, 65, 34, 28,				// 41 - ')'
	5, 42, 28, 127, 28, 42,		// 42 - '*'
	5, 8, 8, 62, 8, 8,			// 43 - '+'
	3, 128, 112, 48,			// 44 - ','
	5, 8, 8, 8, 8, 8,			// 45 - '-'
	1, 64,		// 46 - '.'
	5, 32, 16, 8, 4, 2,			// 47 - '/'
  7, 62, 127, 113, 89, 77, 127, 62, // 48 - '0'
  6, 64, 66, 127, 127, 64, 64,  
  6, 98, 115, 89, 73, 111, 102, 
  6, 34, 99, 73, 73, 127, 54,  
  7, 24, 28, 22, 83, 127, 127, 80,  
  6, 39, 103, 69, 69, 125, 57,  
  6, 60, 126, 75, 73, 121, 48,  
  6, 3, 3, 113, 121, 15, 7,  
  6, 54, 127, 73, 73, 127, 54,  
  6, 6, 79, 73, 105, 63, 30, // 57 - '9'
	1, 20,		// 58 - ':'
	0,		// 59 - ';'
	//5, 56 ,12 ,7 ,4 ,8,		// 60 - '<'
	8, 14, 31, 63, 126, 124, 62, 31, 14, 
	0,		// 61 - '='
	//5,	14, 24 ,112 ,16 ,8,	// 62 - '>'
  8, 0, 6, 15, 30, 60, 30, 15, 6, 
	0,		// 63 - '?'
	6, 3, 3, 56, 68, 68, 68,	// 64 - '@' ----->deg C
	5, 127, 9, 9, 9, 127,		// 65 - 'A'
	5, 127, 73, 73, 73, 54,		// 66 - 'B'
	5, 127, 65, 65, 65, 65,		// 67 - 'C'
	5, 127, 65, 65, 65, 62,		// 68 - 'D'
	5, 127, 73, 73, 73, 73,		// 69 - 'E'
	5, 127, 9, 9, 9, 9,			// 70 - 'F'
	5, 62, 65, 65, 81, 115,		// 71 - 'G'
	5, 127, 8, 8, 8, 127,		// 72 - 'H'
	3, 65, 127, 65,				// 73 - 'I'
	5, 32, 64, 65, 63, 1,		// 74 - 'J'
	5, 127, 8, 20, 34, 65,		// 75 - 'K'
	5, 127, 64, 64, 64, 64,		// 76 - 'L'
	5, 127, 2, 28, 2, 127,		// 77 - 'M'
	5, 127, 4, 8, 16, 127,		// 78 - 'N'
	5, 62, 65, 65, 65, 62,		// 79 - 'O'
	5, 127, 9, 9, 9, 6,			// 80 - 'P'
	5, 62, 65, 81, 33, 94,		// 81 - 'Q'
	5, 127, 9, 25, 41, 70,		// 82 - 'R'
	5, 38, 73, 73, 73, 50,		// 83 - 'S'
	5, 3, 1, 127, 1, 3,			// 84 - 'T'
	5, 63, 64, 64, 64, 63,		// 85 - 'U'
	5, 31, 32, 64, 32, 31,		// 86 - 'V'
	5, 63, 64, 56, 64, 63,		// 87 - 'W'
	5, 99, 20, 8, 20, 99,		// 88 - 'X'
	5, 3, 4, 120, 4, 3,			// 89 - 'Y'
	5, 97, 89, 73, 77, 67,		// 90 - 'Z'
	0,		// 91 - '['
	0,		// 92 - '\'
	0,		// 93 - ']'
	0,		// 94 - '^'
	0,		// 95 - '_'
	0,		// 96 - '`'
	5, 32, 84, 84, 120, 64,		// 97 - 'a'
	5, 127, 40, 68, 68, 56,		// 98 - 'b'
	5, 56, 68, 68, 68, 40,		// 99 - 'c'
	5, 56, 68, 68, 40, 127,		// 100 - 'd'
	5, 56, 84, 84, 84, 24,		// 101 - 'e'
	4, 8, 126, 9, 2,			// 102 - 'f'
	5, 24, 164, 164, 156, 120,	// 103 - 'g'
	5, 127, 8, 4, 4, 120,		// 104 - 'h'
	3, 68, 125, 64,				// 105 - 'i'
	4, 64, 128, 128, 122,		// 106 - 'j'
	4, 127, 16, 40, 68,			// 107 - 'k'
	3, 65, 127, 64,				// 108 - 'l'
	5, 124, 4, 120, 4, 120,		// 109 - 'm'
	5, 124, 8, 4, 4, 120,		// 110 - 'n'
	5, 56, 68, 68, 68, 56,		// 111 - 'o'
	5, 252, 24, 36, 36, 24,		// 112 - 'p'
	5, 24, 36, 36, 24, 252,		// 113 - 'q'
	5, 124, 8, 4, 4, 8,			// 114 - 'r'
	5, 72, 84, 84, 84, 36,		// 115 - 's'
	4, 4, 63, 68, 36,			// 116 - 't'
	5, 60, 64, 64, 32, 124,		// 117 - 'u'
	5, 28, 32, 64, 32, 28,		// 118 - 'v'
	5, 60, 64, 48, 64, 60,		// 119 - 'w'
	5, 68, 40, 16, 40, 68,		// 120 - 'x'
	5, 76, 144, 144, 144, 124,	// 121 - 'y'
	5, 68, 100, 84, 76, 68,		// 122 - 'z'
	0,		// 123 - '{'
	1, 127,		// 124 - '|'
	0,		// 125
	0,		// 126
	0,		// 127
	0,		// 128
	0,		// 129
	0,		// 130
	0,		// 131
	0,		// 132
	0,		// 133
	0,		// 134
	0,		// 135
	0,		// 136
	0,		// 137
	0,		// 138
	0,		// 139
	0,		// 140
	0,		// 141
	0,		// 142
	0,		// 143
	0,		// 144
	0,		// 145
	0,		// 146
	0,		// 147
	0,		// 148
	0,		// 149
	0,		// 150
	0,		// 151
	0,		// 152
	0,		// 153
	0,		// 154
	0,		// 155
	0,		// 156
	0,		// 157
	0,		// 158
	0,		// 159
  7, 33, 117, 85, 84, 60, 120, 64,    // 160 - 'à'
  7, 32, 116, 84, 85, 61, 121, 64,    // 161 - 'á'
  0,    // 162
  0,    // 163
  0,    // 164
  0,    // 165
  0,    // 166
  0,    // 167   
  6, 57, 125, 85, 84, 92, 24, // 168 - è
  6, 56, 124, 84, 85, 93, 25, // 169 - é 
  0,    // 170
  0,    // 171
  5, 1, 69, 125, 124, 64, // 172 - ì
  4, 68, 125, 125, 65,    // 173 - í
  0,    // 174
  0,    // 175
  0,    // 176
  0,    // 177
  6, 57, 125, 69, 68, 124, 56,      // 178 - ò 
  6, 56, 124, 68, 69, 125, 57,      // 179 - ó 
  0,    // 180
  0,    // 181
  0,    // 182
  5, 8, 8, 42, 8, 8,    // 183 - ÷
  0,    // 184
  7, 61, 125, 65, 64, 60, 124, 64,   // 185 - ù 
  7, 60, 124, 64, 65, 61, 125, 64,   // 186 - ú  
	0,		// 187
	0,		// 188
	0,		// 189
	0,		// 190
	0,		// 191
	0,		// 192
	0,		// 193
	0,		// 194
	0,		// 195
	0,		// 196
	0,		// 197
  0,    // 198
  0,    // 199
  0,    // 200
8, 60, 126, 255, 255, 255, 255, 126, 60, //Pacman
8, 60, 126, 255, 255, 255, 231, 102, 36, 
7, 60, 126, 255, 255, 231, 231, 66, 
7, 60, 126, 126, 255, 231, 195, 129, 
7, 254, 123, 243, 127, 243, 123, 254, //Ghost
7, 254, 115, 251, 127, 243, 123, 254, 
7, 254, 123, 243, 127, 251, 115, 254, 
7, 254, 115, 251, 127, 243, 123, 254,  
4, 24, 60, 60, 24, //Ball
	0,		// 210
8, 145, 66, 24, 61, 188, 24, 66, 137,   // SNOW       211
8, 170, 85, 170, 85, 170, 85, 170, 85,  // RAIN       212
8, 30, 33, 33, 45, 38, 34, 34, 28,      // CLOUD      213
8, 158, 97, 161, 97, 166, 98, 34, 28,   // SHOWERS    214
8, 165, 66, 165, 24, 24, 165, 66, 165,  // SNOW       215
8, 14, 145, 81, 177, 22, 18, 18, 12,    // STORM      216
8, 28, 34, 98, 34, 44, 100, 36, 24, 		// LIGHT RAIN 217
8, 145, 66, 24, 61, 188, 38, 34, 28, 		// VARIABLE   218
8, 148, 0, 33, 8, 128, 36, 1, 72, 		  // FOG        219
	0,		// 220
	0,		// 221
	0,		// 222
	0,		// 223
	0,		// 224
	0,		// 225
	0,		// 226
	0,		// 227
	0,		// 228
	0,		// 229
	0,		// 230
	0,		// 231
	0,		// 232
	0,		// 233
	0,		// 234
	0,		// 235
	0,		// 236
	0,		// 237
	0,		// 238
	0,		// 239
	0,		// 240
	0,		// 241
	0,		// 242
	0,		// 243
	0,		// 244
	0,		// 245
	0,		// 246
	0,		// 247
	0,		// 248
	0,		// 249
	0,		// 250
	0,		// 251
	0,		// 252
	0,		// 253
	0,		// 254
	0,		// 255
};

#endif
#ifndef FONTDATA_H2
#define FONTDATA_H2

uint8_t myChars[] = {
  0,    // 0
  0,    // 1
  0,    // 2
  0,    // 3
  0,    // 4
  0,    // 5
  0,    // 6
  0,    // 7
  0,    // 8
  0,    // 9
  0,    // 10
  0,    // 11
  0,    // 12
  0,    // 13
  0,    // 14
  0,    // 15
  0,    // 16
  0,    // 17
  0,    // 18
  0,    // 19
  0,    // 20
  0,    // 21
  0,    // 22
  0,    // 23
  0,    // 24
  0,    // 25
  0,    // 26
  0,    // 27
  0,    // 28
  0,    // 29
  0,    // 30
  0,    // 31
  2, 0, 0,   // 32 - 'Space'
  1, 95,            // 33 - '!'
  3, 7, 0, 7,         // 34 - '"'
  5, 20, 127, 20, 127, 20,  // 35 - '#'
  5, 36, 42, 127, 42, 18,   // 36 - '$'
  5, 35, 19, 8, 100, 98,    // 37 - '%'
  5, 54, 73, 85, 34, 80,    // 38 - '&'
  3, 8, 7, 3,         // 39 - '''
  3, 28, 34, 65,        // 40 - '('
  3, 65, 34, 28,        // 41 - ')'
  5, 42, 28, 127, 28, 42,   // 42 - '*'
  5, 8, 8, 62, 8, 8,      // 43 - '+'
  3, 128, 112, 48,      // 44 - ','
  5, 8, 8, 8, 8, 8,     // 45 - '-'
  1, 64,    // 46 - '.'
  5, 32, 16, 8, 4, 2,     // 47 - '/'
  7, 62, 127, 113, 89, 77, 127, 62, // 48 - '0'
  6, 64, 66, 127, 127, 64, 64,  
  6, 98, 115, 89, 73, 111, 102, 
  6, 34, 99, 73, 73, 127, 54,  
  7, 24, 28, 22, 83, 127, 127, 80,  
  6, 39, 103, 69, 69, 125, 57,  
  6, 60, 126, 75, 73, 121, 48,  
  6, 3, 3, 113, 121, 15, 7,  
  6, 54, 127, 73, 73, 127, 54,  
  6, 6, 79, 73, 105, 63, 30, // 57 - '9'
  1, 20,    // 58 - ':'
  3, 128, 236, 108,    // 59 - ';'
  //5, 56 ,12 ,7 ,4 ,8,   // 60 - '<'
  8, 14, 31, 63, 126, 124, 62, 31, 14, 
  0,    // 61 - '='
  //5,  14, 24 ,112 ,16 ,8, // 62 - '>'
  8, 0, 6, 15, 30, 60, 30, 15, 6, 
  0,    // 63 - '?'
  6, 3, 3, 56, 68, 68, 68,  // 64 - '@' ----->deg C
  6, 124, 126, 19, 19, 126, 124,  //A
  7, 65, 127, 127, 73, 73, 127, 54,  
  7, 28, 62, 99, 65, 65, 99, 34, 
  7, 65, 127, 127, 65, 99, 62, 28, 
  7, 65, 127, 127, 73, 93, 65, 99, 
  7, 65, 127, 127, 73, 29, 1, 3, 
  7, 28, 62, 99, 65, 81, 115, 114, 
  6, 127, 127, 8, 8, 127, 127,  
  5, 0, 65, 127, 127, 65,
  7, 48, 112, 64, 65, 127, 63, 1, 
  7, 65, 127, 127, 8, 28, 119, 99, 
  7, 65, 127, 127, 65, 64, 96, 112, 
  7, 127, 127, 14, 28, 14, 127, 127,  
  7, 127, 127, 6, 12, 24, 127, 127,  
  7, 28, 62, 99, 65, 99, 62, 28, 
  7, 65, 127, 127, 73, 9, 15, 6, 
  6, 30, 63, 33, 113, 127, 94,  
  7, 65, 127, 127, 9, 25, 127, 102, 
  6, 38, 111, 77, 89, 115, 50,  
  6, 3, 65, 127, 127, 65, 3, 
  6, 127, 127, 64, 64, 127, 127,  
  6, 31, 63, 96, 96, 63, 31, 
  7, 127, 127, 48, 24, 48, 127, 127, 
  7, 67, 103, 60, 24, 60, 103, 67,  
  6, 7, 79, 120, 120, 79, 7, 
  7, 71, 99, 113, 89, 77, 103, 115, //Z
  0,    // 91 - '['
  0,    // 92 - '\'
  0,    // 93 - ']'
  0,    // 94 - '^'
  0,    // 95 - '_'
  0,    // 96 - '`'
  7, 32, 116, 84, 84, 60, 120, 64, // - 'a'
  7, 65, 127, 63, 72, 72, 120, 48,  
  6, 56, 124, 68, 68, 108, 40,  
  7, 48, 120, 72, 73, 63, 127, 64,  
  6, 56, 124, 84, 84, 92, 24,  
  6, 72, 126, 127, 73, 3, 2,  
  7, 152, 188, 164, 164, 248, 124, 4,  
  7, 65, 127, 127, 8, 4, 124, 120, 
  5, 0, 68, 125, 125, 64, 
  6, 96, 224, 128, 128, 253, 125,  
  7, 65, 127, 127, 16, 56, 108, 68,  
  5, 0, 65, 127, 127, 64, 
  7, 124, 124, 24, 56, 28, 124, 120,  
  6, 124, 124, 4, 4, 124, 120, 
  6, 56, 124, 68, 68, 124, 56,  
  7, 132, 252, 248, 164, 36, 60, 24, 
  7, 24, 60, 36, 164, 248, 252, 132,  
  7, 68, 124, 120, 76, 4, 28, 24, 
  6, 72, 92, 84, 84, 116, 36,  
  6, 0, 4, 62, 127, 68, 36,  
  7, 60, 124, 64, 64, 60, 124, 64,  
  6, 28, 60, 96, 96, 60, 28, 
  7, 60, 124, 112, 56, 112, 124, 60,  
  7, 68, 108, 56, 16, 56, 108, 68,  
  6, 156, 188, 160, 160, 252, 124,  
  6, 76, 100, 116, 92, 76, 100,      // 122 - 'z'
  0,    // 123 - '{'
  1, 127,   // 124 - '|'
  0,    // 125
  0,    // 126
  0,    // 127
  0,    // 128
  0,    // 129
  0,    // 130
  0,    // 131
  0,    // 132
  0,    // 133
  0,    // 134
  0,    // 135
  0,    // 136
  0,    // 137
  0,    // 138
  0,    // 139
  0,    // 140
  0,    // 141
  0,    // 142
  0,    // 143
  0,    // 144
  0,    // 145
  0,    // 146
  0,    // 147
  0,    // 148
  0,    // 149
  0,    // 150
  0,    // 151
  0,    // 152
  0,    // 153
  0,    // 154
  0,    // 155
  0,    // 156
  0,    // 157
  0,    // 158
  0,    // 159
  7, 33, 117, 85, 84, 60, 120, 64,    // 160 - 'à'
  7, 32, 116, 84, 85, 61, 121, 64,    // 161 - 'á'
  0,    // 162
  0,    // 163
  0,    // 164
  0,    // 165
  0,    // 166
  0,    // 167   
  6, 57, 125, 85, 84, 92, 24, // 168 - è
  6, 56, 124, 84, 85, 93, 25, // 169 - é 
  0,    // 170
  0,    // 171
  5, 1, 69, 125, 124, 64, // 172 - ì
  4, 68, 125, 125, 65,    // 173 - í
  0,    // 174
  0,    // 175
  0,    // 176
  0,    // 177
  6, 57, 125, 69, 68, 124, 56,      // 178 - ò 
  6, 56, 124, 68, 69, 125, 57,      // 179 - ó 
  0,    // 180
  0,    // 181
  0,    // 182
  5, 8, 8, 42, 8, 8,    // 183 - ÷
  0,    // 184
  7, 61, 125, 65, 64, 60, 124, 64,   // 185 - ù 
  7, 60, 124, 64, 65, 61, 125, 64,   // 186 - ú  
  0,    // 187
  0,    // 188
  0,    // 189
  0,    // 190
  0,    // 191
  0,    // 192
  0,    // 193
  0,    // 194
  0,    // 195
  0,    // 196
  0,    // 197
  0,    // 198
8, 60, 126, 255, 255, 255, 255, 126, 60, //Pacman
8, 60, 126, 255, 255, 255, 231, 102, 36, 
8, 60, 126, 255, 255, 231, 231, 66, 0,
8, 60, 126, 126, 255, 231, 195, 129, 0,
8, 60, 126, 255, 255, 231, 231, 66, 0,
8, 60, 126, 255, 255, 255, 231, 102, 36, 
8, 254, 123, 243, 127, 243, 123, 254, 0, //Ghost
8, 254, 115, 251, 127, 243, 123, 254, 0,
8, 254, 123, 243, 127, 251, 115, 254, 0,
8, 254, 115, 251, 127, 243, 123, 254, 0,
4, 24, 60, 60, 24, 0, 0, //Ball
0, // 210
0,    // 211
0,    // 212
0,    // 213
0,    // 214
0,    // 215
0,    // 216
0,    // 217
0,    // 218
0,    // 219
0,    // 220
0,    // 221
0,    // 222
0,    // 223
0,    // 224
0,    // 225
0,    // 226
0,    // 227
0,    // 228
0,    // 229
0,    // 230
  0,    // 231
  0,    // 232
  0,    // 233
  0,    // 234
  0,    // 235
  0,    // 236
  0,    // 237
  0,    // 238
  0,    // 239
  0,    // 240
  0,    // 241
  0,    // 242
  0,    // 243
  0,    // 244
  0,    // 245
  0,    // 246
  0,    // 247
  0,    // 248
  0,    // 249
  0,    // 250
  0,    // 251
  0,    // 252
  0,    // 253
  0,    // 254
  0,    // 255
};

#endif

animation.ino

Arduino
Animation are defined here
//animazione = 250 * 20 = 4 secondi
uint8_t ghost_scene = 0;
uint32_t  lastTimeAnimation = 0;
bool animazione() {
  if (millis() - lastTimeAnimation >= 250) //ogni 1 secondi
  {
    lastTimeAnimation = millis();
    if (ghost_scene < 20) {
      parola.setTextAlignment(0, PA_LEFT);
      switch (ghost_scene) {
        case 0:
          sprintf(szMesg, "%c %c %c %c %c %c %c %c %c %c %c", 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209);
          break;
        case 1:
          sprintf(szMesg, "%c %c %c %c %c %c %c %c %c %c %c", 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, (205 + ghost_scene % 4));
          break;
        case 2:
          sprintf(szMesg, "%c %c %c %c %c %c %c %c %c %c %c", 209, 209, 209, 209, 209, 209, 209, 209, 209, (205 + ghost_scene % 4), 209);
          break;
        case 3:
          sprintf(szMesg, "%c %c %c %c %c %c %c %c %c %c %c", 209, 209, 209, 209, 209, 209, 209, 209, (205 + ghost_scene % 4), 209, 209);
          break;
        case 4:
          sprintf(szMesg, "%c %c %c %c %c %c %c %c %c %c %c", 209, 209, 209, 209, 209, 209, 209, (205 + ghost_scene % 4), 209, 209, 209);
          break;
        case 5:
          sprintf(szMesg, "%c %c %c %c %c %c %c %c %c %c %c", 209, 209, 209, 209, 209, 209, 209, (205 + ghost_scene % 4), 209, 209, 209);
          break;
        case 6:
          sprintf(szMesg, "%c %c %c %c %c %c %c %c %c %c %c", 209, 209, 209, 209, 209, 209, (205 + ghost_scene % 4), 209, 209, 209, 209);
          break;
        case 7:
          sprintf(szMesg, "%c %c %c %c %c %c %c %c %c %c %c", 209, 209, 209, 209, (205 + ghost_scene % 4), 209, 209, 209, 209, 209, 209);
          break;
        case 8:
          sprintf(szMesg, "%c %c %c %c %c %c %c %c %c %c %c", 209, 209, 209, (205 + ghost_scene % 4), 209, 209, 209, 209, 209, 209, 209);
          break;
        case 9:
          sprintf(szMesg, "%c %c %c %c %c %c %c %c %c %c %c", 209, 209, (205 + ghost_scene % 4), 209, 209, 209, 209, 209, 209, 209, 209);
          break;
        case 10:
          sprintf(szMesg, "%c %c %c %c %c %c %c %c %c %c %c", 209, 209, (205 + ghost_scene % 4), 209, 209, 209, 209, 209, 209, 209, 209);
          break;
        case 11:
          sprintf(szMesg, "%c %c %c %c %c %c %c %c %c %c %c", 209, 209, 209, (205 + ghost_scene % 4), 209, 209, 209, 209, 209, 209, 209);
          break;
        case 12:
          sprintf(szMesg, "%c %c %c %c %c %c %c %c %c %c %c", 209, 209, 209, 209, (205 + ghost_scene % 4), 209, 209, 209, 209, 209, 209);
          break;
        case 13:
          sprintf(szMesg, "%c %c %c %c %c %c %c %c %c %c %c", 209, 209, 209, (205 + ghost_scene % 4), 209, 209, 209, 209, 209, 209, 209);
          break;
        case 14:
          sprintf(szMesg, "%c %c %c %c %c %c %c %c %c %c %c", 209, 209, 209, (205 + ghost_scene % 4), 209, 209, 209, 209, 209, 209, 209);
          break;
        case 15:
          sprintf(szMesg, "%c %c %c %c %c %c %c %c %c %c %c", 209, 209, 209, 209, (205 + ghost_scene % 4), 209, 209, 209, 209, 209, 209);
          break;
        case 16:
          sprintf(szMesg, "%c %c %c %c %c %c %c %c %c %c %c", 209, 209, 209, (205 + ghost_scene % 4), 209, 209, 209, 209, 209, 209, 209);
          break;
        case 17:
          sprintf(szMesg, "%c %c %c %c %c %c %c %c %c %c %c", 209, 209, (205 + ghost_scene % 4), 209, 209, 209, 209, 209, 209, 209, 209);
          break;
        case 18:
          sprintf(szMesg, "%c %c %c %c %c %c %c %c %c %c %c", 209, (205 + ghost_scene % 4), 209, 209, 209, 209, 209, 209, 209, 209, 209);
          break;
        case 19:
          sprintf(szMesg, "%c %c %c %c %c %c %c %c %c %c %c", (205 + ghost_scene % 4), 209, 209, 209, 209, 209, 209, 209, 209, 209, 209);
          break;
        default:
          break;
      }
      ghost_scene++;
    } else {
      ghost_scene = 0;
      parola.setTextAlignment(0, PA_CENTER);
      return false;
    }
  }
  return true;
}
uint8_t flashing = 0;
bool animazioneTime(enum textEffect_t entra , enum textEffect_t esce , int tempo_display_timer) {
  if (millis() - lastTimeAnimation >= 500) //ogni 1 secondo
  {
    if (flashing == 0) {
      //entra
      parola.setTextAlignment(0, PA_CENTER);
      parola.setTextEffect(0, entra, PA_NO_EFFECT);
      getTime(szMesg);
      flashing++;
    } else if (flashing < tempo_display_time) {
      //flashing
      parola.setTextEffect(0, PA_PRINT, PA_NO_EFFECT);
      parola.setTextAlignment(0, PA_CENTER);
      lastTimeAnimation = millis();
      getTime(szMesg, flashing % 2==0);
      flashing++;
    } else if (flashing == tempo_display_time) {
      //esce
      parola.setTextEffect(0, PA_NO_EFFECT, esce);
      getTime(szMesg);
      flashing++;
    } else {
      parola.setTextAlignment(0, PA_LEFT);
      flashing = 0;
      return false;
    }
  }
  return true;
}

bool animazioneTimer(enum textEffect_t entra , enum textEffect_t esce , int tempo_display_timer) {
  if (millis() - lastTimeAnimation >= 500) //every second
  {
    if (flashing == 0) {
      //entra
      parola.setTextAlignment(0, PA_CENTER);
      parola.setTextEffect(0, entra, PA_NO_EFFECT);
      getTimer(szMesg, flashing % 2==0);
      flashing++;
    } else if (flashing < tempo_display_timer) {
      //flashing
      parola.setTextEffect(0, PA_PRINT, PA_NO_EFFECT);
      parola.setTextAlignment(0, PA_CENTER);
      lastTimeAnimation = millis();
      getTimer(szMesg, flashing % 2==0);
      flashing++;
    } else if (flashing == tempo_display_timer) {
      //esce
      parola.setTextEffect(0, PA_NO_EFFECT, esce);
      getTimer(szMesg, flashing % 2==0);
      flashing++;
    } else {
      parola.setTextAlignment(0, PA_LEFT);
      flashing = 0;
      return false;
    }
  }
  return check_timer_on();
}

display.ino

Arduino
void set_message(const char* cmd, int off) {
  //DEBUG_PRINTLN(cmd);
  String str(cmd);
  message = str.substring(off);
}
void set_allert(const char* cmd, int off) {
  allertOn = true;
  String str(cmd);
  allert = str.substring(off);
}
void set_allert(const char* my_allert) {
  set_allert(my_allert,0);
}

  
void unset_allert() {
  allertOn = false;
  parola.setIntensity(intensity);
}

void set_time(const char* cmd, int off) {
  tmElements_t tmSet;
  time_t tSet;
  tmSet.Year = 1000 * (cmd[off] - '0') + 100 * (cmd[off + 1] - '0') + 10 * (cmd[off + 2] - '0') + cmd[off + 3] - '0' - 1970;
  tmSet.Month = 10 * (cmd[off + 5] - '0') + cmd[off + 6] - '0';
  tmSet.Day = 10 * (cmd[off + 8] - '0') + cmd[off + 9] - '0';
  tmSet.Hour = 10 * (cmd[off + 11] - '0') + cmd[off + 12] - '0';
  tmSet.Minute = 10 * (cmd[off + 14] - '0') + cmd[off + 15] - '0';
  tmSet.Second = 10 * (cmd[off + 17] - '0') + cmd[off + 18] - '0';
  tSet = makeTime(tmSet);         //convert to time_t
  setTime(tSet);                          //set the local time
  breakTime(now(), tmSet);        //convert the current local time back to tmElements_t (to ensure weekday is calculated)
}
void set_timer(const char* cmd, int off) {
  timer[0] = millis()/1000;
  uint32_t timer_hour = 10 * (cmd[off] - '0') + cmd[off + 1] - '0';
  uint32_t timer_min = 10 * (cmd[off + 3] - '0') + cmd[off + 4] - '0';
  uint32_t timer_sec = 10 * (cmd[off + 6] - '0') + cmd[off + 7] - '0';
  timer[1] = timer_sec + timer_min * 60 + timer_hour * 3600;
}
void displayon_1(const char* cmd, int off) {
  PREF_h_m_s_on_1[0] = 10 * (cmd[off] - '0') + cmd[off + 1] - '0' ;
  PREF_h_m_s_on_1[1] = 10 * (cmd[off + 3] - '0') +  cmd[off + 4] - '0';
  PREF_h_m_s_on_1[2] = 10 * (cmd[off + 6] - '0') +  cmd[off + 7] - '0';
  save("h_on_1",PREF_h_m_s_on_1[0]);
  save("m_on_1",PREF_h_m_s_on_1[1]);
  save("s_on_1",PREF_h_m_s_on_1[2]);
  DEBUG_PRINTLN(cmd);
}
void displayoff_1(const char* cmd, int off) {
  PREF_h_m_s_off_1[0] = 10 * (cmd[off] - '0') + cmd[off + 1] - '0' ;
  PREF_h_m_s_off_1[1] = 10 * (cmd[off + 3] - '0') +  cmd[off + 4] - '0';
  PREF_h_m_s_off_1[2] = 10 * (cmd[off + 6] - '0') +  cmd[off + 7] - '0';
  save("h_off_1",PREF_h_m_s_off_1[0]);
  save("m_off_1",PREF_h_m_s_off_1[1]);
  save("s_off_1",PREF_h_m_s_off_1[2]);
  DEBUG_PRINTLN(cmd);
}
void displayon_2(const char* cmd, int off) {
  PREF_h_m_s_on_2[0] = 10 * (cmd[off] - '0') + cmd[off + 1] - '0' ;
  PREF_h_m_s_on_2[1] = 10 * (cmd[off + 3] - '0') +  cmd[off + 4] - '0';
  PREF_h_m_s_on_2[2] = 10 * (cmd[off + 6] - '0') +  cmd[off + 7] - '0';
  save("h_on_2",PREF_h_m_s_on_2[0]);
  save("m_on_2",PREF_h_m_s_on_2[1]);
  save("s_on_2",PREF_h_m_s_on_2[2]);
  DEBUG_PRINTLN(cmd);
}
void displayoff_2(const char* cmd, int off) {
  PREF_h_m_s_off_2[0] = 10 * (cmd[off] - '0') + cmd[off + 1] - '0' ;
  PREF_h_m_s_off_2[1] = 10 * (cmd[off + 3] - '0') +  cmd[off + 4] - '0';
  PREF_h_m_s_off_2[2] = 10 * (cmd[off + 6] - '0') +  cmd[off + 7] - '0';
  save("h_off_2",PREF_h_m_s_off_2[0]);
  save("m_off_2",PREF_h_m_s_off_2[1]);
  save("s_off_2",PREF_h_m_s_off_2[2]);
  DEBUG_PRINTLN(cmd);
}
void active_autostdby() {
  autostdbyActivate = true;
}
void deactive_autostdby() {
  autostdbyActivate = false;
}
void set_icon(const char* cmd, int off) {
  STATO_SCORRI_PACMAN = -1;
  String str(cmd);
  icon = str.substring(off);
}
void unset_icon() {
  STATO_SCORRI_PACMAN = 0;
}
void set_intensity(const char* cmd, int off) {
  int i = atoi(cmd);
  intensity = i % 16;
  parola.setIntensity(intensity);
}
void set_speed(const char* cmd, int off) {
  speed = atoi(cmd);
  parola.setSpeed(speed);
}
void set_wifi(const char* cmd, int off) {
  int i = atoi(cmd);
}
void reset() {
  ESP.restart();
}
void invert() {
  parola.setInvert(!parola.getInvert());
}
void on() {
  parola.displayShutdown(false);
  STATO_GET_DISPLAY_ON = true;
}
void off() {
  parola.displayShutdown(true);
  STATO_GET_DISPLAY_ON = false;
}
void display_reset() {
  off();
  //delay(1000);
  on();
  //P.displayReset();
}
void initParola(boolean conn_left) {
      parola.begin(3);
      parola.setInvert(false);
  
      parola.setFont(0, myChars);
      parola.setFont(1, jF_Custom);
      parola.setFont(2, myChars);
      
      setOrientation(conn_left);
      
      parola.setIntensity(intensity);
      parola.addChar('^', colonT);

}
void setOrientation(boolean conn_left) {
  if(conn_left) {
      parola.setZone(0, 1, MAX_DEVICES - 1);
      parola.setZone(1, 0 , 0 );
      parola.setZone(2, 0, MAX_DEVICES - 1);
      parola.setZoneEffect(0, true, PA_FLIP_UD);
      parola.setZoneEffect(1, true, PA_FLIP_UD);
      parola.setZoneEffect(2, true, PA_FLIP_UD);
      parola.setZoneEffect(0, true, PA_FLIP_LR);
      parola.setZoneEffect(1, true, PA_FLIP_LR);
      parola.setZoneEffect(2, true, PA_FLIP_LR);
      setZone();
  } else {
      parola.setZone(0, 0, MAX_DEVICES - 2);
      parola.setZone(1, MAX_DEVICES - 1 , MAX_DEVICES - 1 );
      parola.setZone(2, 0, MAX_DEVICES - 1);
      parola.setZoneEffect(0, false, PA_FLIP_UD);
      parola.setZoneEffect(1, false, PA_FLIP_UD);
      parola.setZoneEffect(2, false, PA_FLIP_UD);
      parola.setZoneEffect(0, false, PA_FLIP_LR);
      parola.setZoneEffect(1, false, PA_FLIP_LR);
      parola.setZoneEffect(2, false, PA_FLIP_LR);
      setZone();
  }
}

void setZone() {
            parola.displayZoneText(0, szMesg, PA_CENTER, speed, 0, PA_NO_EFFECT, PA_NO_EFFECT);
            parola.displayZoneText(1, szSolo, !flipped()?PA_LEFT:PA_RIGHT, speed, PAUSE_TIME, PA_PRINT, PA_NO_EFFECT);
            parola.displayZoneText(2, szMesg, PA_CENTER, speed, PAUSE_TIME, PA_PRINT, PA_NO_EFFECT);
}

boolean flipped() {
  return parola.getZoneEffect(0, PA_FLIP_LR);
}

enum textEffect_t pa_scroll_left () {
  if(flipped()) return PA_SCROLL_RIGHT;
  return PA_SCROLL_LEFT;
}
enum textEffect_t pa_scroll_right () {
  if(flipped()) return PA_SCROLL_LEFT;
  return PA_SCROLL_RIGHT;
}
enum textEffect_t pa_scroll_up () {
  if(flipped()) return PA_SCROLL_DOWN;
  return PA_SCROLL_UP;
}
enum textEffect_t pa_scroll_down () {
  if(flipped()) return PA_SCROLL_UP;
  return PA_SCROLL_DOWN;
}

void disegna_barra(int number_of_lines) {
  char line = '|';
  if(number_of_lines > CONST_DISPLAY_MAX_LINES) number_of_lines = CONST_DISPLAY_MAX_LINES;
  VAR_BARRA_STRING[0] = number_of_lines;
}

Credits

Tony

Tony

1 project • 2 followers

Comments