En esta entrada realizaremos un mini TV utilizando la ya conocida ESP32 y una pantalla TFT de 1.65 pulgadas de la marca WavesShare. Esta mini TV es ideal para ver los resultados de los partidos de futbol como la Eurocopa, Copa America, Liga MX y mas torneos o deportes, así como para otras aplicaciones como monitorear el clima de tu ciudad entre otras muchas aplicaciones mas.
Componentes.
Pare este proyecto ocupamos los siguientes componentes.
- Pantalla TFT 1.69″ de la marca WavesShare
- ESP32
- Stand o Carcasa para la pantalla (opcional)
Carcasa para Mini TV (Opcional).
Como primer paso diseñamos un stand para la pantalla en nuestro caso lo diseñaremos para que se vea como una televisión antigua gracias a la forma rectangular de esta, este paso es opcional nosotros lo haremos así para una mejor presentación de este proyecto. En la pagina de WavesShare obtuvimos las medidas de la pantalla, buscamos una referencia de TV antigua y con esto realizamos un modelo para imprimir.
Desarrollo de la Aplicación.
En este ejemplo desarrollaremos una aplicación para ver en la mini TV los resultados de los partidos de futbol del dia en curso, para esto nuestra aplicación constara de tres partes:
- Servidor NTP, para obtener la fecha y hora.
- API-Football, para obtener los resultados de los partidos del día y los próximos partidos.
- Función Main Page, para imprimir en la pantalla la información obtenida como banderas de los equipos, resultados etc,…
Teniendo los tres puntos explicados anteriormente juntaremos todos para obtener nuestra aplicación.
Servidor NTP
A continuación explicaremos el código de programación utilizado para nuestro servidor NTP.
Iniciamos declarando las librerías Wifi y Time y enseguida ingresamos las claves de internet para la conexión por wifi del ESP32.
#include "WiFi.h" #include "time.h" // Claves internet const char* ssid = "SSID"; const char* password = "Your Password";
Enseguida configuramos el servidor para obtener la fecha y la hora, en este caso utilizaremos “pool.ntp.org” en esta parte lo mas importante es configurar el Offset en segundos de la región en la que nos encontramos utilizando el uso horario en nuestro caso la ciudad de monterrey tiene el uso horario GTM-6 para definir el Offset basta con una simple multiplicación, (-6 * 3600), -6 por el uso horario de nuestra ubicación y 3600 por los segundos que tiene una hora, esta multiplicación nos da un resultado de -21600 que es el valor que le daremos a nuestro Offset.
const char* ntpServer = "pool.ntp.org"; const long gmtOffset_sec = -21600; const int daylightOffset_sec = 0;
Por ultimo declaramos dos variables tipo string “todayDate” para almacenar la fecha actual y “fixtureReq” para almacenar el request que queremos solicitar a la API-Football.
String todayDate; String fixtureReq;
En el void setup iniciamos el serial, nos conectamos al Wifi y configuramos el servidor.
void setup() { // Iniciar serial Serial.begin(115200); // Conectar al WiFi Serial.print("Intentando conectarse a la red: "); Serial.println(ssid); WiFi.begin(ssid, password); // Esperar conectarse a la red: while (WiFi.status() != WL_CONNECTED) { Serial.print("."); // Esperar un segundo para reintentar delay(1000); } Serial.print("\nConectado a: "); Serial.println(ssid); // Configurar tiempo configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); }
En el void loop estaremos obteniendo el tiempo cada cinco segundos con la función “getLocalTime” dentro de esta función se declara una estructura del tipo “tm timeinfo” la cual es una estructura estándar en ANSI C con la cual obtenemos la fecha y la hora con el formato que necesitamos. Esta fecha obtenida nos servirá como parámetro en nuestro request para API-Football y así obtendremos los resultados de los partidos del día en curso.
void loop() { // Obtener fecha y tiempo actual getLocalTime(); delay(5000); } void getLocalTime(){ // Crear una estructura tm llamda timeinfo struct tm timeinfo; // Esperar para obtener el tiempo local if(!getLocalTime(&timeinfo)){ Serial.println("Failed to obtain time"); return; } Serial.println("Fecha y tiempo actual:"); // Obtener la fecha char formattedDate[16]; strftime(formattedDate, sizeof(formattedDate), "%Y-%m-%d", &timeinfo); Serial.print("Fecha: "); Serial.println(formattedDate); // Obtener la hora char formattedTime[16]; strftime(formattedTime, sizeof(formattedTime), "%H:%M", &timeinfo); Serial.print("Hora: "); Serial.println(formattedTime); // Imprimir request fixtureReq = String("/v3/fixtures?date=") + formattedDate + String("&league=4&season=2024&timezone=America%2FMonterrey"); Serial.print("Url: "); Serial.println(fixtureReq); }
Cargamos el codigo a la ESP32 y al final deberíamos de ver como se imprime la fecha, enseguida la hora y por ultimo el request que utilizaremos para la API-Football con la fecha que generamos con el servidor NTP.
API-Football
A continuación se muestra el código de programación para obtener los resultados de los partidos de la API-Football, por ser este muy extenso se recomiendo que vean la explicación de este en el video que mostraremos mas adelante.
#include <WiFiClientSecure.h> #include <ArduinoJson.h> #include "WiFi.h" // Claves internet const char* ssid = "SSID"; const char* password = "PASSWORD"; // Server api-football const char* serverName = "api-football-v1.p.rapidapi.com"; String host = "api-football-v1.p.rapidapi.com"; String apiKey = "Your-Api-Key"; //Certificado del server const char* test_root_ca = "-----BEGIN CERTIFICATE-----\n" "MIIEdTCCA12gAwIBAgIJAKcOSkw0grd/MA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV\n" "BAYTAlVTMSUwIwYDVQQKExxTdGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTIw\n" "MAYDVQQLEylTdGFyZmllbGQgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0\n" "eTAeFw0wOTA5MDIwMDAwMDBaFw0zNDA2MjgxNzM5MTZaMIGYMQswCQYDVQQGEwJV\n" "UzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTElMCMGA1UE\n" "ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjE7MDkGA1UEAxMyU3RhcmZp\n" "ZWxkIFNlcnZpY2VzIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IC0gRzIwggEi\n" "MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVDDrEKvlO4vW+GZdfjohTsR8/\n" "y8+fIBNtKTrID30892t2OGPZNmCom15cAICyL1l/9of5JUOG52kbUpqQ4XHj2C0N\n" "Tm/2yEnZtvMaVq4rtnQU68/7JuMauh2WLmo7WJSJR1b/JaCTcFOD2oR0FMNnngRo\n" "Ot+OQFodSk7PQ5E751bWAHDLUu57fa4657wx+UX2wmDPE1kCK4DMNEffud6QZW0C\n" "zyyRpqbn3oUYSXxmTqM6bam17jQuug0DuDPfR+uxa40l2ZvOgdFFRjKWcIfeAg5J\n" "Q4W2bHO7ZOphQazJ1FTfhy/HIrImzJ9ZVGif/L4qL8RVHHVAYBeFAlU5i38FAgMB\n" "AAGjgfAwge0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0O\n" "BBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMB8GA1UdIwQYMBaAFL9ft9HO3R+G9FtV\n" "rNzXEMIOqYjnME8GCCsGAQUFBwEBBEMwQTAcBggrBgEFBQcwAYYQaHR0cDovL28u\n" "c3MyLnVzLzAhBggrBgEFBQcwAoYVaHR0cDovL3guc3MyLnVzL3guY2VyMCYGA1Ud\n" "HwQfMB0wG6AZoBeGFWh0dHA6Ly9zLnNzMi51cy9yLmNybDARBgNVHSAECjAIMAYG\n" "BFUdIAAwDQYJKoZIhvcNAQELBQADggEBACMd44pXyn3pF3lM8R5V/cxTbj5HD9/G\n" "VfKyBDbtgB9TxF00KGu+x1X8Z+rLP3+QsjPNG1gQggL4+C/1E2DUBc7xgQjB3ad1\n" "l08YuW3e95ORCLp+QCztweq7dp4zBncdDQh/U90bZKuCJ/Fp1U1ervShw3WnWEQt\n" "8jxwmKy6abaVd38PMV4s/KCHOkdp8Hlf9BRUpJVeEXgSYCfOn8J3/yNTd126/+pZ\n" "59vPr5KW7ySaNRB6nJHGDn2Z9j8Z3/VyVOEVqQdZe4O/Ui5GjLIAZHYcSNPYeehu\n" "VsyuLAOQ1xk4meTKCRlb/weWsKh/NEnfVqn3sF/tM+2MR7cwA130A4w=\n" "-----END CERTIFICATE-----\n"; // Datos de los requests String fixtureReq = "/v3/fixtures?date=2024-06-30&league=4&season=2024&timezone=America/Monterrey"; String nextGamesReq = "/v3/fixtures?&league=4&season=2024&next=4&timezone=America/Monterrey"; String eventReq; // Constantes const int maxFixtures = 6; const int maxGoals = 20; // Varibles int fixturesResults = 0; int eventsResults = 0; int goalsCounter = 0; int isGameLiveSum = 0; int todayGames = 1; int isGameLive[maxFixtures]; int firstTeamGoalsCounterArray[maxFixtures]; int secondTeamGoalsCounterArray[maxFixtures]; String eventType; String matchGoals; String gameDate; String gameTime; String fixtureID[maxFixtures]; String eventDate[maxFixtures]; String gameStatus[maxFixtures]; String timeElapsed[maxFixtures]; String extraTime[maxFixtures]; String firstTeam[maxFixtures]; String firstTeamGoals[maxFixtures]; String firstTeamPenaltyGoals[maxFixtures]; String secondTeam[maxFixtures]; String secondTeamGoals[maxFixtures]; String secondTeamPenaltyGoals[maxFixtures]; String firstTeamPlayerGoal[maxFixtures][maxGoals]; String firstTeamMinuteGoal[maxFixtures][maxGoals]; String secondTeamPlayerGoal[maxFixtures][maxGoals]; String secondTeamMinuteGoal[maxFixtures][maxGoals]; // Definimos el cliente WiFiClientSecure client; void setup() { // Iniciar serial Serial.begin(115200); // Conectar al WiFi Serial.print("Intentando conectarse a la red: "); Serial.println(ssid); WiFi.begin(ssid, password); // Esperar conectarse a la red: while (WiFi.status() != WL_CONNECTED) { Serial.print("."); // Esperar un segundo para reintentar delay(1000); } Serial.print("Conectado a: "); Serial.println(ssid); // Configurar certificado client.setCACert(test_root_ca); // Realizar un fixture request con los partidos de la fecha indicada getFixtureData(fixtureReq); // Ver si hay partidos en la fecha indicada if (todayGames == 0) { // De no ser así imprimir la info de los siguientes cuatro fixtures Serial.println("No se encontraron fixtures la fecha indicada, solicitando los siguientes cuatro partidos"); getFixtureData(nextGamesReq); } else { // De ser así obtener la información de los fixtures del día Serial.print("Se encontraron "); Serial.print(fixturesResults); Serial.println(" fixtures la fecha indicada"); } // Imprimir en el serial la información printFixturesData(); // Si hay partidos en la fecha indicada obtener los eventos if (todayGames > 0) { for (int i = 0; i < fixturesResults; i++) { // Construir el request de los evenfos fixture por fixture Serial.print("Solicitando eventos del fixture: "); Serial.println(fixtureID[i]); eventReq = String("/v3/fixtures/events") + String("?fixture=") + fixtureID[i]; // Realizar la solicitud getEventsData(i, eventReq); } // Imprimir los eventos gol en el serial printEventsData(); } } void loop() { // Si hay partidos en el día if (todayGames == 0) { // De no ser así obtener la información de los siguientes cuatro fixtures getFixtureData(nextGamesReq); } else { // De ser así obtener la información de los fixtures del día getFixtureData(fixtureReq); } // Imprimir la cantidad de fixtures encontrados con la información de los fixtures Serial.print("Se encontraron "); Serial.print(fixturesResults); Serial.println(" fixtures la fecha indicada"); printFixturesData(); // Imprimir los eventos de los fixtures sólo si están en vivo for (int i = 0; i < fixturesResults; i++) { if (isGameLive[i]) { Serial.print("Solicitando eventos del fixture: "); Serial.println(fixtureID[i]); eventReq = String("/v3/fixtures/events") + String("?fixture=") + fixtureID[i]; getEventsData(i, eventReq); } } printEventsData(); // Esperar un minuto delay(60000); } void getFixtureData(String req) { String result; //Conectar al servidor Serial.println("\nStarting connection to server..."); client.setTimeout(15000); if (!client.connect(serverName, 443)) { Serial.println("Connection failed!"); return; } Serial.println("Connected to server!"); // Solicitud GET client.print(String("GET ") + req + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "X-RapidAPI-Key: " + apiKey + "\r\n" + "Connection: close\r\n\r\n"); // Esperar a la respuesta del servidor while (client.connected() && !client.available()) { delay(10); } // Leer respuesta while (client.connected() || client.available()) { if (client.available()) { result = client.readStringUntil('\n'); Serial.println(result); } } // Cerrar la conexión Serial.println("Closing connection"); client.stop(); // Deserializar información de la respuesta JsonDocument doc; DeserializationError error = deserializeJson(doc, result); Serial.println("Deserializing api data"); if (error) { Serial.print("deserializeJson() failed: "); Serial.println(error.c_str()); return; } Serial.println("Deserialize succesfull"); fixturesResults = doc["results"]; if (fixturesResults == 0 && req == fixtureReq) { todayGames = 0; } int fixtureCounter = 0; // Leer información de la respuesta por fixture for (JsonObject response_item : doc["response"].as<JsonArray>()) { JsonObject response_item_fixture = response_item["fixture"]; fixtureID[fixtureCounter] = String(response_item_fixture["id"]); eventDate[fixtureCounter] = String(response_item_fixture["date"]); JsonObject response_item_fixture_status = response_item_fixture["status"]; gameStatus[fixtureCounter] = String(response_item_fixture_status["short"]); timeElapsed[fixtureCounter] = String(response_item_fixture_status["elapsed"]); JsonObject response_teams = response_item["teams"]; firstTeam[fixtureCounter] = String(response_teams["home"]["name"]); secondTeam[fixtureCounter] = String(response_teams["away"]["name"]); firstTeamGoals[fixtureCounter] = String(response_item["goals"]["home"]); secondTeamGoals[fixtureCounter] = String(response_item["goals"]["away"]); for (JsonPair response_item_score_item : response_item["score"].as<JsonObject>()) { if (response_item_score_item.key().c_str() == "penalty") { firstTeamPenaltyGoal[fixtureCounter] = response_item_score_item.value()["home"]; secondTeamPenaltyGoal[fixtureCounter] = response_item_score_item.value()["away"]; } } if (gameStatus[fixtureCounter] == "1H" || gameStatus[fixtureCounter] == "2H" || gameStatus[fixtureCounter] == "ET" || gameStatus[fixtureCounter] == "P") { isGameLive[fixtureCounter] = 1; } else { isGameLive[fixtureCounter] = 0; } fixtureCounter += 1; } } void getEventsData(int fixtureNumber, String req) { String result; //Conectar al servidor Serial.println("\nStarting connection to server..."); client.setTimeout(15000); if (!client.connect(serverName, 443)) { Serial.println("Connection failed!"); return; } Serial.println("Connected to server!"); // Solicitud GET client.print(String("GET ") + req + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "X-RapidAPI-Key: " + apiKey + "\r\n" + "Connection: close\r\n\r\n"); // Esperar a la respuesta del servidor while (client.connected() && !client.available()) { delay(10); } // Leer respuesta while (client.connected() || client.available()) { if (client.available()) { result = client.readStringUntil('\n'); Serial.println(result); } } // Cerrar la conexión Serial.println("Closing connection"); client.stop(); // Deserializar información de la respuesta JsonDocument doc; DeserializationError error = deserializeJson(doc, result); Serial.println("Deserializing api data"); if (error) { Serial.print("deserializeJson() failed: "); Serial.println(error.c_str()); return; } Serial.println("Deserialize succesfull"); int eventsCounter = 0; int firstTeamGoalsCounter = 0; int secondTeamGoalsCounter = 0; String extraTime = ""; // Leer información de la respuesta por evento for (JsonObject response_item : doc["response"].as<JsonArray>()) { extraTime = ""; // Si el evento es tipo Goal if (response_item["type"] == "Goal") { JsonObject response_item_team = response_item["team"]; // Si es del primer equipo if (firstTeam[fixtureNumber] == response_item_team["name"]) { firstTeamPlayerGoal[fixtureNumber][firstTeamGoalsCounter] = String(response_item["player"]["name"]); extraTime = String(response_item["time"]["extra"]); // Si no fue en tiempo añadido if (extraTime == "null") { firstTeamMinuteGoal[fixtureNumber][firstTeamGoalsCounter] = String(response_item["time"]["elapsed"]) + "'"; } // Si fue en tiempo añadido else { firstTeamMinuteGoal[fixtureNumber][firstTeamGoalsCounter] = String(response_item["time"]["elapsed"]) + "+" + extraTime + "'"; } firstTeamGoalsCounter += 1; } // Si es del segundo equipo if (secondTeam[fixtureNumber] == response_item_team["name"]) { secondTeamPlayerGoal[fixtureNumber][secondTeamGoalsCounter] = String(response_item["player"]["name"]); extraTime = String(response_item["time"]["extra"]); // Si no fue en tiempo añadido if (extraTime == "null") { secondTeamMinuteGoal[fixtureNumber][secondTeamGoalsCounter] = String(response_item["time"]["elapsed"]) + "'"; } // Si fue en tiempo añadido else { secondTeamMinuteGoal[fixtureNumber][secondTeamGoalsCounter] = String(response_item["time"]["elapsed"]) + "+" + extraTime + "'"; } secondTeamGoalsCounter += 1; } } } } void printFixturesData() { for (int i = 0; i < fixturesResults; i++) { Serial.print("Id: "); Serial.println(fixtureID[i]); Serial.print("Primer equipo: "); Serial.println(firstTeam[i]); Serial.print("Segundo equipo: "); Serial.println(secondTeam[i]); Serial.print("Date: "); Serial.println(eventDate[i]); Serial.print("El partido está en vivo: "); Serial.println(isGameLive[i]); Serial.print("Game Status: "); Serial.println(gameStatus[i]); Serial.print("Elapsed: "); Serial.println(timeElapsed[i]); Serial.print("Goles primer equipo: "); Serial.println(firstTeamGoals[i]); Serial.print("Goles segundo equipo: "); Serial.println(secondTeamGoals[i]); } } void printEventsData() { for (int i = 0; i < fixturesResults; i++) { Serial.print("Anotadores de "); Serial.println(firstTeam[i]); for (int j = 0; j < firstTeamGoals[i].toInt(); j++) { Serial.print(firstTeamPlayerGoal[i][j]); Serial.print(" "); Serial.println(firstTeamMinuteGoal[i][j]); } Serial.print("Anotadores de "); Serial.println(secondTeam[i]); for (int j = 0; j < secondTeamGoals[i].toInt(); j++) { Serial.print(secondTeamPlayerGoal[i][j]); Serial.print(" "); Serial.println(secondTeamMinuteGoal[i][j]); } } }
Conexiones ESP32 – Pantalla.
A continuación se muestra las tabla para las conexiones entre el ESP32 y la Pantalla LCD de 1.69″.
Codigo de programación Pantalla.
Ahora solo nos queda realizar la programación para la pantalla LCD para esto ademas de la fecha, la hora y la información de los partidos tambien ocupamos generar las banderas de los equipos que esten jugando cada partido. Para este caso mostraremos en la pantalla los resultados de los partidos de la Eurocopa Alemania 2024, es por esto que debemos de generar la bandera de cada una de las selecciones participantes, al ser esto muy laborioso optamos por el uso de una de las herramientas mas utilizadas actualmente la Inteligencia Artificial a la cual le solicitamos nos genere el codigo para cada bander. El codigo de programación quedo de la siguiente manera:
#include <Adafruit_GFX.h> #include <Adafruit_ST7789.h> #include <SPI.h> // Pines TFT #define TFT_CS 5 #define TFT_RST 32 #define TFT_DC 33 // Colores texto #define ORANGE_TEXT 0xDAE0 #define GREY_TEXT 0xEF7D #define BLACK_TEXT 0x31C6 #define GREEN_TEXT 0x0680 // Colores banderas #define WHITE 0xFFFF #define BLACK 0x0000 #define RED 0xF800 #define GREEN 0x07E0 #define BLUE 0x001F #define YELLOW 0xFFE0 #define ORANGE 0xFD20 #define PURPLE 0x780F #define CYAN 0x07FF #define LIGHT_BLUE 0x5D9E // Enum de Países enum countries { PORTUGAL, CZECH, SPAIN, FRANCE, GERMANY, ITALY, ENGLAND, GEORGIA, SWITZERLAND, SCOTLAND, HUNGARY, ROMANIA, SLOVAKIA, BELGIUM, UKRAINE, AUSTRIA, POLAND, NETHERLANDS, SERBIA, SLOVENIA, DENMARK, CROATIA, ALBANIA, TURKEY }; // Declarar pantalla tft Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST); void setup() { // Iniciar serial Serial.begin(115200); // Inicializar pantalla TFT tft.init(240, 280); tft.setRotation(3); tft.fillScreen(GREY_TEXT); tft.setTextSize(3); drawtext("Iniciando", BLACK_TEXT, 60, 110); delay(1000); // Mostrar página principal mainPage(); } void loop() { } // Función para imprimir texto en pantalla tft void drawtext(String text, uint16_t color, int x, int y) { tft.setCursor(x, y); tft.setTextColor(color); tft.setTextWrap(true); tft.print(text); } // Funciones para dibujar banderas void drawPortugalFlag(int x_center, int y_center) { int radius = 20; // Radio para un diámetro de 40 píxeles // Dibujar el fondo (verde y rojo) for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { int x_pos = x_center + x; int y_pos = y_center + y; if (x < 0) { tft.drawPixel(x_pos, y_pos, GREEN); } else { tft.drawPixel(x_pos, y_pos, RED); } } } } // Dibujar el círculo amarillo central (escudo) for (int y = -10; y <= 10; y++) { for (int x = -10; x <= 10; x++) { if (x * x + y * y <= 10 * 10) { tft.drawPixel(x_center - 5 + x, y_center + y, YELLOW); } } } // Dibujar el círculo rojo dentro del círculo amarillo for (int y = -7; y <= 7; y++) { for (int x = -7; x <= 7; x++) { if (x * x + y * y <= 7 * 7) { tft.drawPixel(x_center - 5 + x, y_center + y, RED); } } } // Dibujar el círculo blanco dentro del círculo rojo for (int y = -5; y <= 5; y++) { for (int x = -5; x <= 5; x++) { if (x * x + y * y <= 5 * 5) { tft.drawPixel(x_center - 5 + x, y_center + y, WHITE); } } } // Detalles del escudo (cruces azules) for (int i = -1; i <= 1; i++) { tft.drawPixel(x_center - 5 - 2 + i, y_center, BLUE); tft.drawPixel(x_center - 5 + 2 + i, y_center, BLUE); tft.drawPixel(x_center - 5 - 1, y_center - 1 + i, BLUE); tft.drawPixel(x_center - 5 + 1, y_center - 1 + i, BLUE); tft.drawPixel(x_center - 5, y_center - 2 + i, BLUE); tft.drawPixel(x_center - 5, y_center + 2 + i, BLUE); } // Castillos amarillos int castles[12][2] = { {-8, -5}, {-8, 5}, {-6, -7}, {-6, 7}, {0, -7}, {0, 7}, {2, -5}, {2, 5}, {4, -5}, {4, 5}, {4, -7}, {4, 7} }; for (int i = 0; i < 12; i++) { tft.drawPixel(x_center - 5 + castles[i][0], y_center + castles[i][1], YELLOW); } } void drawCzechFlag(int x_center, int y_center) { int radius = 20; // 40 pixels diameter, radius is half // Dibujar el círculo y la bandera dentro de él for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { if (x < 0 && abs(x) >= abs(y)) { tft.drawPixel(x_center + x, y_center + y, BLUE); // Triángulo azul } else if (y <= 0) { tft.drawPixel(x_center + x, y_center + y, WHITE); // Parte superior blanca } else { tft.drawPixel(x_center + x, y_center + y, RED); // Parte inferior roja } } } } } void drawSpainFlag(int x_center, int y_center) { int radius = 20; for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { tft.drawPixel(x_center + x, y_center + y, RED); if (y >= -radius / 3 && y <= radius / 3) { tft.drawPixel(x_center + x, y_center + y, YELLOW); } } } } } void drawFranceFlag(int x_center, int y_center) { int radius = 20; for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { if (x < -radius / 3) { tft.drawPixel(x_center + x, y_center + y, BLUE); } else if (x > radius / 3) { tft.drawPixel(x_center + x, y_center + y, RED); } else { tft.drawPixel(x_center + x, y_center + y, WHITE); } } } } } void drawGermanyFlag(int x_center, int y_center) { int radius = 20; for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { if (y < -radius / 3) { tft.drawPixel(x_center + x, y_center + y, BLACK); } else if (y > radius / 3) { tft.drawPixel(x_center + x, y_center + y, YELLOW); } else { tft.drawPixel(x_center + x, y_center + y, RED); } } } } } void drawItalyFlag(int x_center, int y_center) { int radius = 20; for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { if (x < -radius / 3) { tft.drawPixel(x_center + x, y_center + y, GREEN); } else if (x > radius / 3) { tft.drawPixel(x_center + x, y_center + y, RED); } else { tft.drawPixel(x_center + x, y_center + y, WHITE); } } } } } void drawEnglandFlag(int x_center, int y_center) { int radius = 20; // 40 pixels diameter, radius is half int cross_thickness = 6; // Grosor de la cruz // Dibujar el círculo blanco de fondo for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { tft.drawPixel(x_center + x, y_center + y, WHITE); } } } // Dibujar la línea vertical de la cruz for (int i = -radius; i <= radius; i++) { for (int j = -cross_thickness / 2; j <= cross_thickness / 2; j++) { if ((i * i + j * j) <= radius * radius) { tft.drawPixel(x_center + j, y_center + i, RED); } } } // Dibujar la línea horizontal de la cruz for (int i = -radius; i <= radius; i++) { for (int j = -cross_thickness / 2; j <= cross_thickness / 2; j++) { if ((i * i + j * j) <= radius * radius) { tft.drawPixel(x_center + i, y_center + j, RED); } } } } void drawGeorgiaFlag(int x_center, int y_center) { int radius = 20; // 40 pixels diameter, radius is half // Dibujar el círculo y la bandera dentro de él for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { tft.drawPixel(x_center + x, y_center + y, WHITE); } } } // Dibujar la cruz central for (int i = -radius; i <= radius; i++) { if (i * i <= radius * radius) { // Línea vertical de la cruz central tft.drawPixel(x_center, y_center + i, RED); tft.drawPixel(x_center - 1, y_center + i, RED); tft.drawPixel(x_center + 1, y_center + i, RED); // Línea horizontal de la cruz central tft.drawPixel(x_center + i, y_center, RED); tft.drawPixel(x_center + i, y_center - 1, RED); tft.drawPixel(x_center + i, y_center + 1, RED); } } // Dibujar las cuatro cruces pequeñas int cross_size = 3; int cross_offset = radius / 2; for (int dy = -1; dy <= 1; dy++) { for (int dx = -1; dx <= 1; dx++) { if (abs(dx) + abs(dy) == 1) { for (int i = -cross_size; i <= cross_size; i++) { // Cruces pequeñas superior izquierda tft.drawPixel(x_center - cross_offset + dx * cross_size, y_center - cross_offset + dy * cross_size + i, RED); tft.drawPixel(x_center - cross_offset + dx * cross_size + i, y_center - cross_offset + dy * cross_size, RED); // Cruces pequeñas superior derecha tft.drawPixel(x_center + cross_offset + dx * cross_size, y_center - cross_offset + dy * cross_size + i, RED); tft.drawPixel(x_center + cross_offset + dx * cross_size + i, y_center - cross_offset + dy * cross_size, RED); // Cruces pequeñas inferior izquierda tft.drawPixel(x_center - cross_offset + dx * cross_size, y_center + cross_offset + dy * cross_size + i, RED); tft.drawPixel(x_center - cross_offset + dx * cross_size + i, y_center + cross_offset + dy * cross_size, RED); // Cruces pequeñas inferior derecha tft.drawPixel(x_center + cross_offset + dx * cross_size, y_center + cross_offset + dy * cross_size + i, RED); tft.drawPixel(x_center + cross_offset + dx * cross_size + i, y_center + cross_offset + dy * cross_size, RED); } } } } } void drawSwitzerlandFlag(int x_center, int y_center) { int radius = 20; // 40 pixels diameter, radius is half // Dibujar el círculo rojo de fondo for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { tft.drawPixel(x_center + x, y_center + y, RED); } } } // Dibujar la cruz blanca int cross_size = 5; for (int i = -cross_size; i <= cross_size; i++) { tft.drawPixel(x_center, y_center + i, WHITE); tft.drawPixel(x_center + i, y_center, WHITE); if (abs(i) <= 2) { tft.drawPixel(x_center - 2, y_center + i, WHITE); tft.drawPixel(x_center + 2, y_center + i, WHITE); tft.drawPixel(x_center + i, y_center - 2, WHITE); tft.drawPixel(x_center + i, y_center + 2, WHITE); } } } void drawScotlandFlag(int x_center, int y_center) { int radius = 20; // 40 pixels diameter, radius is half // Dibujar el círculo azul de fondo for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { tft.drawPixel(x_center + x, y_center + y, LIGHT_BLUE); } } } // Dibujar las dos cruces diagonales blancas int width = 4; // Ancho de la cruz for (int i = -radius; i <= radius; i++) { for (int j = -width; j <= width; j++) { // Diagonal positiva int x1 = i; int y1 = i + j; if (x1 * x1 + y1 * y1 <= radius * radius) { tft.drawPixel(x_center + x1, y_center + y1, WHITE); } // Diagonal negativa int x2 = i; int y2 = -i + j; if (x2 * x2 + y2 * y2 <= radius * radius) { tft.drawPixel(x_center + x2, y_center + y2, WHITE); } } } } void drawHungaryFlag(int x_center, int y_center) { int radius = 20; // 40 pixels diameter, radius is half // Dibujar el círculo y la bandera dentro de él for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { if (y < -radius / 3) { tft.drawPixel(x_center + x, y_center + y, RED); } else if (y > radius / 3) { tft.drawPixel(x_center + x, y_center + y, GREEN); } else { tft.drawPixel(x_center + x, y_center + y, WHITE); } } } } } void drawRomaniaFlag(int x_center, int y_center) { int radius = 20; // 40 pixels diameter, radius is half // Dibujar el círculo y la bandera dentro de él for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { if (x < -radius / 3) { tft.drawPixel(x_center + x, y_center + y, BLUE); } else if (x > radius / 3) { tft.drawPixel(x_center + x, y_center + y, RED); } else { tft.drawPixel(x_center + x, y_center + y, YELLOW); } } } } } void drawSlovakiaFlag(int x_center, int y_center) { int radius = 20; // 40 pixels diameter, radius is half // Dibujar el círculo de fondo de la bandera for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { if (y < -radius / 3) { tft.drawPixel(x_center + x, y_center + y, WHITE); } else if (y > radius / 3) { tft.drawPixel(x_center + x, y_center + y, RED); } else { tft.drawPixel(x_center + x, y_center + y, BLUE); } } } } // Dibujar el escudo simplificado int shield_width = 10; int shield_height = 12; int shield_x = x_center - radius / 2; // Posicionarlo hacia la izquierda int shield_y = y_center - radius / 3; // Posicionarlo ligeramente hacia arriba // Dibujar el contorno del escudo con una parte inferior redondeada for (int y = 0; y <= shield_height; y++) { for (int x = 0; x <= shield_width; x++) { if (x == 0 || x == shield_width || y == 0 || (y == shield_height && (x > 1 && x < shield_width - 1)) || (y > shield_height - 3 && (x == 1 || x == shield_width - 1))) { tft.drawPixel(shield_x + x, shield_y + y, WHITE); } else { tft.drawPixel(shield_x + x, shield_y + y, RED); } } } // Dibujar la cruz blanca en el escudo for (int y = 2; y <= 10; y++) { for (int x = 4; x <= 5; x++) { tft.drawPixel(shield_x + x, shield_y + y, WHITE); } } for (int y = 4; y <= 5; y++) { for (int x = 2; x <= 7; x++) { tft.drawPixel(shield_x + x, shield_y + y, WHITE); } } // Dibujar las montañas azules en el escudo for (int y = 8; y <= 10; y++) { for (int x = 3; x <= 6; x++) { tft.drawPixel(shield_x + x, shield_y + y, BLUE); } } } void drawBelgiumFlag(int x_center, int y_center) { int radius = 20; // 40 pixels diameter, radius is half // Dibujar el círculo y la bandera dentro de él for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { if (x < -radius / 3) { tft.drawPixel(x_center + x, y_center + y, BLACK); } else if (x > radius / 3) { tft.drawPixel(x_center + x, y_center + y, RED); } else { tft.drawPixel(x_center + x, y_center + y, YELLOW); } } } } } void drawUkraineFlag(int x_center, int y_center) { int radius = 20; // 40 pixels diameter, radius is half // Dibujar el círculo y la bandera dentro de él for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { if (y < 0) { tft.drawPixel(x_center + x, y_center + y, BLUE); } else { tft.drawPixel(x_center + x, y_center + y, YELLOW); } } } } } void drawAustriaFlag(int x_center, int y_center) { int radius = 20; // 40 pixels diameter, radius is half // Dibujar el círculo y la bandera dentro de él for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { if (y < -radius / 3) { tft.drawPixel(x_center + x, y_center + y, RED); } else if (y > radius / 3) { tft.drawPixel(x_center + x, y_center + y, RED); } else { tft.drawPixel(x_center + x, y_center + y, WHITE); } } } } } void drawPolandFlag(int x_center, int y_center) { int radius = 20; // 40 pixels diameter, radius is half // Dibujar el círculo y la bandera dentro de él for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { if (y < 0) { tft.drawPixel(x_center + x, y_center + y, WHITE); } else { tft.drawPixel(x_center + x, y_center + y, RED); } } } } } void drawNetherlandsFlag(int x_center, int y_center) { int radius = 20; // 40 pixels diameter, radius is half // Dibujar el círculo y la bandera dentro de él for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { if (y < -radius / 3) { tft.drawPixel(x_center + x, y_center + y, RED); } else if (y > radius / 3) { tft.drawPixel(x_center + x, y_center + y, BLUE); } else { tft.drawPixel(x_center + x, y_center + y, WHITE); } } } } } void drawSerbiaFlag(int x_center, int y_center) { int radius = 20; // 40 pixels diameter, radius is half // Dibujar el círculo de fondo de la bandera for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { if (y < -radius / 3) { tft.drawPixel(x_center + x, y_center + y, RED); } else if (y > radius / 3) { tft.drawPixel(x_center + x, y_center + y, BLUE); } else { tft.drawPixel(x_center + x, y_center + y, WHITE); } } } } // Dibujar el escudo simplificado int shield_radius = 6; int shield_center_x = x_center - radius / 3; // Posicionarlo hacia la izquierda int shield_center_y = y_center - radius / 4; // Posicionarlo ligeramente hacia arriba // Dibujar el contorno del escudo for (int y = -shield_radius; y <= shield_radius; y++) { for (int x = -shield_radius; x <= shield_radius; x++) { if (x * x + y * y <= shield_radius * shield_radius) { tft.drawPixel(shield_center_x + x, shield_center_y + y, RED); } } } // Dibujar la cruz blanca en el escudo int cross_size = 2; for (int y = -cross_size; y <= cross_size; y++) { for (int x = -cross_size; x <= cross_size; x++) { tft.drawPixel(shield_center_x + x, shield_center_y + y, WHITE); } } // Dibujar las coronas amarillas en el escudo int crown_radius = 3; for (int y = -crown_radius; y <= crown_radius; y++) { for (int x = -crown_radius; x <= crown_radius; x++) { if (x * x + y * y <= crown_radius * crown_radius) { tft.drawPixel(shield_center_x + x, shield_center_y - 8 + y, YELLOW); } } } // Dibujar el águila blanca simplificada en el escudo int eagle_width = 4; for (int y = -eagle_width; y <= eagle_width; y++) { for (int x = -eagle_width; x <= eagle_width; x++) { if (abs(x) == eagle_width || abs(y) == eagle_width || (abs(x) <= 2 && abs(y) <= 2)) { tft.drawPixel(shield_center_x + x, shield_center_y + y, WHITE); } } } } void drawSloveniaFlag(int x_center, int y_center) { int radius = 20; // 40 pixels diameter, radius is half // Dibujar el círculo de fondo de la bandera for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { if (y < -radius / 3) { tft.drawPixel(x_center + x, y_center + y, WHITE); } else if (y > radius / 3) { tft.drawPixel(x_center + x, y_center + y, RED); } else { tft.drawPixel(x_center + x, y_center + y, LIGHT_BLUE); } } } } // Dibujar el escudo simplificado int shield_radius = 6; int shield_center_x = x_center - radius / 3; // Posicionarlo hacia la izquierda int shield_center_y = y_center - radius / 3; // Posicionarlo ligeramente hacia arriba // Dibujar el contorno del escudo for (int y = -shield_radius; y <= shield_radius; y++) { for (int x = -shield_radius; x <= shield_radius; x++) { if (x * x + y * y <= shield_radius * shield_radius) { tft.drawPixel(shield_center_x + x, shield_center_y + y, BLUE); } } } // Dibujar las montañas blancas en el escudo int mountain_height = 3; for (int y = -mountain_height; y <= mountain_height; y++) { for (int x = -mountain_height; x <= mountain_height; x++) { if (y == -x || y == x || y == mountain_height) { tft.drawPixel(shield_center_x + x, shield_center_y + y, WHITE); } } } // Dibujar las estrellas amarillas en el escudo int star_points[5][2] = { { 0, -2 }, { 1, 0 }, { 2, 0 }, { 1, 1 }, { 0, 1 } }; for (int i = 0; i < 5; i++) { tft.drawPixel(shield_center_x + star_points[i][0], shield_center_y - 5 + star_points[i][1], YELLOW); tft.drawPixel(shield_center_x + star_points[i][0] - 2, shield_center_y - 4 + star_points[i][1], YELLOW); tft.drawPixel(shield_center_x + star_points[i][0] + 2, shield_center_y - 4 + star_points[i][1], YELLOW); } } void drawDenmarkFlag(int x_center, int y_center) { int radius = 20; // 40 pixels diameter, radius is half // Dibujar el círculo rojo de fondo for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { tft.drawPixel(x_center + x, y_center + y, RED); } } } // Dibujar la cruz blanca int cross_thickness = 6; // Grosor de la cruz int cross_offset = 2; // Desplazamiento de la línea horizontal de la cruz hacia arriba // Dibujar la línea vertical de la cruz for (int i = -radius; i <= radius; i++) { for (int j = -cross_thickness / 2; j <= cross_thickness / 2; j++) { if ((i * i + j * j) <= radius * radius) { tft.drawPixel(x_center + j - cross_offset, y_center + i, WHITE); } } } // Dibujar la línea horizontal de la cruz for (int i = -radius; i <= radius; i++) { for (int j = -cross_thickness / 2; j <= cross_thickness / 2; j++) { if ((i * i + j * j) <= radius * radius) { tft.drawPixel(x_center + i, y_center + j, WHITE); } } } } void drawCroatiaFlag(int x_center, int y_center) { int radius = 20; // 40 pixels diameter, radius is half // Dibujar el círculo y la bandera dentro de él for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { if (y < -radius / 3) { tft.drawPixel(x_center + x, y_center + y, RED); } else if (y > radius / 3) { tft.drawPixel(x_center + x, y_center + y, BLUE); } else { tft.drawPixel(x_center + x, y_center + y, WHITE); } } } } // Dibujar el escudo central simplificado int shield_radius = 5; for (int y = -shield_radius; y <= shield_radius; y++) { for (int x = -shield_radius; x <= shield_radius; x++) { if (x * x + y * y <= shield_radius * shield_radius) { tft.drawPixel(x_center + x, y_center + y, RED); if ((x + y) % 2 == 0) { tft.drawPixel(x_center + x, y_center + y, WHITE); } } } } } void drawAlbaniaFlag(int x_center, int y_center) { int radius = 20; // 40 pixels diameter, radius is half // Dibujar el círculo rojo de fondo for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { tft.drawPixel(x_center + x, y_center + y, RED); } } } // Dibujar el águila negra simplificada (rectángulo negro en el centro) for (int y = -5; y <= 5; y++) { for (int x = -5; x <= 5; x++) { tft.drawPixel(x_center + x, y_center + y, BLACK); } } } void drawTurkeyFlag(int x_center, int y_center) { int radius = 20; // 40 pixels diameter, radius is half // Dibujar el círculo rojo de fondo for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius) { tft.drawPixel(x_center + x, y_center + y, RED); } } } // Dibujar el semicírculo blanco (luna) int moon_radius_outer = 8; int moon_radius_inner = 6; int moon_offset_x = -5; // Offset para centrar la luna a la izquierda for (int y = -moon_radius_outer; y <= moon_radius_outer; y++) { for (int x = -moon_radius_outer; x <= moon_radius_outer; x++) { if (x * x + y * y <= moon_radius_outer * moon_radius_outer) { tft.drawPixel(x_center + moon_offset_x + x, y_center + y, WHITE); } } } for (int y = -moon_radius_inner; y <= moon_radius_inner; y++) { for (int x = -moon_radius_inner; x <= moon_radius_inner; x++) { if (x * x + y * y <= moon_radius_inner * moon_radius_inner) { tft.drawPixel(x_center + moon_offset_x + 2 + x, y_center + y, RED); } } } // Dibujar la estrella blanca inclinada int star_center_x = x_center + 7; int star_center_y = y_center - 3; int star_size = 3; // Tamaño de la estrella // Coordenadas relativas de la estrella inclinada hacia la izquierda int star_points[10][2] = { { 0, -star_size }, { star_size / 2, -star_size / 2 }, { star_size, -star_size }, { star_size / 2, star_size / 2 }, { star_size, star_size }, { 0, star_size / 2 }, { -star_size, star_size }, { -star_size / 2, star_size / 2 }, { -star_size, -star_size }, { -star_size / 2, -star_size / 2 } }; for (int i = 0; i < 10; i++) { tft.drawPixel(star_center_x + star_points[i][0], star_center_y + star_points[i][1], WHITE); } } // Crear array de funciones typedef void (*DrawFlagArray)(int, int); DrawFlagArray drawFlagArray[] = { drawPortugalFlag, drawCzechFlag, drawSpainFlag, drawFranceFlag, drawGermanyFlag, drawItalyFlag, drawEnglandFlag, drawGeorgiaFlag, drawSwitzerlandFlag, drawScotlandFlag, drawHungaryFlag, drawRomaniaFlag, drawSlovakiaFlag, drawBelgiumFlag, drawUkraineFlag, drawAustriaFlag, drawPolandFlag, drawNetherlandsFlag, drawSerbiaFlag, drawSloveniaFlag, drawDenmarkFlag, drawCroatiaFlag, drawAlbaniaFlag, drawTurkeyFlag }; // Obtener el valor de la posición del array de funciones de la bandera deseada countries getCountry(String country) { if (country == "Portugal") return PORTUGAL; if (country == "Czech Republic") return CZECH; if (country == "Spain") return SPAIN; if (country == "France") return FRANCE; if (country == "Germany") return GERMANY; if (country == "Italy") return ITALY; if (country == "England") return ENGLAND; if (country == "Georgia") return GEORGIA; if (country == "Switzerland") return SWITZERLAND; if (country == "Scotland") return SCOTLAND; if (country == "Hungary") return HUNGARY; if (country == "Romania") return ROMANIA; if (country == "Slovakia") return SLOVAKIA; if (country == "Belgium") return BELGIUM; if (country == "Ukraine") return UKRAINE; if (country == "Austria") return AUSTRIA; if (country == "Poland") return POLAND; if (country == "Netherlands") return NETHERLANDS; if (country == "Serbia") return SERBIA; if (country == "Slovenia") return SLOVENIA; if (country == "Denmark") return DENMARK; if (country == "Croatia") return CROATIA; if (country == "Albania") return ALBANIA; if (country == "Türkiye") return TURKEY; return PORTUGAL; // Default case, handle as needed } // Dibujar bandera con switch case void drawFlag(String flag, int x, int y) { countries country = getCountry(flag); switch (country) { case GERMANY: drawFlagArray[GERMANY](x, y); break; case ALBANIA: drawFlagArray[ALBANIA](x, y); break; case AUSTRIA: drawFlagArray[AUSTRIA](x, y); break; case BELGIUM: drawFlagArray[BELGIUM](x, y); break; case CROATIA: drawFlagArray[CROATIA](x, y); break; case CZECH: drawFlagArray[CZECH](x, y); break; case DENMARK: drawFlagArray[DENMARK](x, y); break; case ENGLAND: drawFlagArray[ENGLAND](x, y); break; case FRANCE: drawFlagArray[FRANCE](x, y); break; case GEORGIA: drawFlagArray[GEORGIA](x, y); break; case HUNGARY: drawFlagArray[HUNGARY](x, y); break; case ITALY: drawFlagArray[ITALY](x, y); break; case NETHERLANDS: drawFlagArray[NETHERLANDS](x, y); break; case POLAND: drawFlagArray[POLAND](x, y); break; case PORTUGAL: drawFlagArray[PORTUGAL](x, y); break; case ROMANIA: drawFlagArray[ROMANIA](x, y); break; case SCOTLAND: drawFlagArray[SCOTLAND](x, y); break; case SERBIA: drawFlagArray[SERBIA](x, y); break; case SLOVAKIA: drawFlagArray[SLOVAKIA](x, y); break; case SLOVENIA: drawFlagArray[SLOVENIA](x, y); break; case SPAIN: drawFlagArray[SPAIN](x, y); break; case SWITZERLAND: drawFlagArray[SWITZERLAND](x, y); break; case TURKEY: drawFlagArray[TURKEY](x, y); break; case UKRAINE: drawFlagArray[UKRAINE](x, y); break; default: Serial.println("País no reconocido"); break; } } // Imprimir página principal tft void mainPage() { Serial.print("Mostrando partido de "); Serial.println("Portugal vs Georgia"); // EURO2024 tft.fillScreen(BLACK_TEXT); tft.setTextSize(4); drawtext("EURO2024", GREY_TEXT, 47, 6); // Fecha tft.setTextSize(2); tft.fillRoundRect(70, 45, 140, 20, 4, ORANGE_TEXT); drawtext("2024-06-30", BLACK_TEXT, 80, 48); // Hora a empezar /Minutos / Finalizado tft.setTextSize(2); drawtext("13:00", ORANGE_TEXT, 110, 80); // Marcador tft.setTextSize(5); drawtext(" - ", GREY_TEXT, 68, 100); // Banderas drawFlag("Portugal", 30, 116); drawFlag("Georgia", 245, 116); //Nombre de jugadores que anotaron con minuto tft.setTextSize(1.5); drawtext("Quaresma", GREY_TEXT, 10, 150); drawtext("2'", GREY_TEXT, 110, 150); drawtext("L. Dvali", GREY_TEXT, 145, 150); drawtext("1'", GREY_TEXT, 240, 150); }
Para comprender de mejor manera este código se recomienda ver el video explicativo que les dejaremos en esta entrada mas adelante.
Codigo Final
Para esta parte solo basta con juntar los tres códigos generados anteriormente con la diferencia que la declaración de las funciones y demás se agregaron a un archivo .h llamado “Football_Data.h” y en el código principal queda solo la aplicación. Todos los archivos utilizados en este proyecto se dejaran en un enlace de descarga mas adelante.
#include <Adafruit_GFX.h> #include <Adafruit_ST7789.h> #include <SPI.h> #include <WiFiClientSecure.h> #include <ArduinoJson.h> #include "WiFi.h" #include "Football_Data.h" #include "time.h" void setup(void) { // Iniciar serial Serial.begin(115200); // Conectar al WiFi Serial.print("Intentando conectarse a la red: "); Serial.println(ssid); WiFi.begin(ssid, password); // Esperar conectarse a la red: while (WiFi.status() != WL_CONNECTED) { Serial.print("."); // Esperar un segundo para reintentar delay(1000); } Serial.print("Conectado a: "); Serial.println(ssid); // Inicializar pantalla TFT tft.init(240, 280); tft.setRotation(3); tft.fillScreen(GREY_TEXT); tft.setTextSize(3); testdrawtext("Iniciando", BLACK_TEXT, 55, 100); delay(1000); // Init and get the time configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); getLocalTime(); // Configurar certificado client.setCACert(test_root_ca); getFixtureData(fixtureReq); // Ver si hay partidos en la fecha indicada if (todayGames == 0) { // De no ser así imprimir la info de los siguientes cuatro fixtures Serial.println("No se encontraron fixtures la fecha indicada, solicitando los siguientes cuatro partidos"); getFixtureData(nextGamesReq); } else if (nextGames == 0) { // De ser así obtener la información de los fixtures del día Serial.println("No se encontraron próximos fixtures, solicitando los últimos cuatro partidos"); getFixtureData(lastGamesReq); } else { Serial.print("Se encontraron "); Serial.print(fixturesResults); Serial.println(" fixtures la fecha indicada"); } // Imprimir en el serial la información printFixturesData(); // Si hay partidos en la fecha indicada obtener los eventos if (nextGames == 1) { for (int i = 0; i < fixturesResults; i++) { // Construir el request de los evenfos fixture por fixture Serial.print("Solicitando eventos del fixture: "); Serial.println(fixtureID[i]); eventsReq = String("/v3/fixtures/events") + String("?fixture=") + fixtureID[i]; // Realizar la solicitud getEventsData(i, eventsReq); } // Imprimir los eventos gol en el serial printEventsData(); } mainPage(); maxRequestsCounter = round((60 / (fixturesResults * 8))); } void loop() { getLocalTime(); if (requestCounter > maxRequestsCounter) { requestCounter = 0; } mainPage(); requestCounter += 1; } void mainPage() { for (int i = 0; i < fixturesResults; i++) { String startTime = extractTime(eventDate[i]); if ((isGameLive[i] || (localTime.substring(0, 2) == startTime.substring(0, 2))) && (requestCounter == maxRequestsCounter)) { getFixtureData(fixtureReq); Serial.print("Fuxture en vivo: "); Serial.println(isGameLive[i]); eventsReq = String("/v3/fixtures/events") + String("?fixture=") + fixtureID[i]; Serial.print("Solicitando el siguiente request: "); Serial.println(eventsReq); getEventsData(i, eventsReq); // ExtraTime if (((timeElapsed[i] == "45") && (maxTimeReached[i] == 0)) || ((timeElapsed[i] == "90") && (maxTimeReached[i] == 0))) { int extraTimeHourStart = localTime.substring(0, 2).toInt(); int extraTimeMinuteStart = localTime.substring(3).toInt(); extraTimeStart[i] = (extraTimeHourStart * 60) + (extraTimeMinuteStart); maxTimeReached[i] = 1; } } else { delay(8000); } // printFixturesData(); printEventsData(); Serial.print("Mostrando partido de "); Serial.println(firstTeam[i] + " vs " + secondTeam[i]); // EURO2024 tft.fillScreen(BLACK_TEXT); tft.setTextSize(4); testdrawtext("EURO2024", GREY_TEXT, 47, 6); // Fecha tft.setTextSize(2); tft.fillRoundRect(70, 45, 140, 20, 4, ORANGE_TEXT); gameDate = extractDate(eventDate[i]); testdrawtext(gameDate, BLACK_TEXT, 80, 48); // Hora a empezar /Minutos / Finalizado tft.setTextSize(2); if (gameStatus[i] == "NS") { gameTime = extractTime(eventDate[i]); testdrawtext(gameTime, GREY_TEXT, 110, 80); } else if (gameStatus[i] == "FT" || gameStatus[i] == "AET" || gameStatus[i] == "PEN") { testdrawtext("Finalizado", ORANGE_TEXT, 85, 80); maxTimeReached[i] = 0; } else if (gameStatus[i] == "1H" || gameStatus[i] == "2H" || gameStatus[i] == "ET") { Serial.print("MaxTimeReached"); Serial.println(maxTimeReached[i]); localTimeMinutes = (localTime.substring(0, 2).toInt() * 60) + localTime.substring(3).toInt(); extratimeElapsed[i] = String(localTimeMinutes - extraTimeStart[i]); Serial.print("MaxTimeReached"); Serial.println(localTimeMinutes); Serial.print("MaxTimeReached"); Serial.println(extratimeElapsed[i]); if (maxTimeReached[i] == 0 || extratimeElapsed[i] == "0") { testdrawtext(timeElapsed[i] + "'", GREEN_TEXT, 130, 80); } else { testdrawtext(timeElapsed[i] + "+" + extratimeElapsed[i] + "'", GREEN_TEXT, 115, 80); } } else if (gameStatus[i] == "BT") { testdrawtext("Descanso", GREEN_TEXT, 100, 80); maxTimeReached[i] = 0; } else if (gameStatus[i] == "P") { testdrawtext("Penalties", GREEN_TEXT, 90, 80); maxTimeReached[i] = 0; } else if (gameStatus[i] == "HT") { testdrawtext("Medio Tiempo", GREEN_TEXT, 68, 80); maxTimeReached[i] = 0; } // Marcador tft.setTextSize(5); if (firstTeamGoals[i] == "null" && secondTeamGoals[i] == "null") { testdrawtext(" - ", GREY_TEXT, 68, 100); } else { matchGoals = firstTeamGoals[i] + " - " + secondTeamGoals[i]; testdrawtext(matchGoals, GREY_TEXT, 68, 100); } // En caso de penalties if (gameStatus[i] == "PEN" || gameStatus[i] == "P") { matchGoals = firstTeamPenaltyGoals[i] + " - " + secondTeamPenaltyGoals[i]; tft.setTextSize(1); testdrawtext("PEN", GREY_TEXT, 131, 125); tft.setTextSize(2); testdrawtext(matchGoals, GREY_TEXT, 111, 130); } // Banderas drawFlag(firstTeam[i], 30, 116); drawFlag(secondTeam[i], 245, 116); //Nombre Jugadores Primer equipo tft.setTextSize(1.5); for (int counter = 0; counter < firstTeamGoals[i].toInt(); counter++) { testdrawtext(firstTeamPlayerGoal[i][counter], GREY_TEXT, 10, 150 + (playerYGap * counter)); testdrawtext(firstTeamMinuteGoal[i][counter], GREY_TEXT, 110, 150 + (playerYGap * counter)); } for (int counter = 0; counter < secondTeamGoals[i].toInt(); counter++) { testdrawtext(secondTeamPlayerGoal[i][counter], GREY_TEXT, 145, 150 + (playerYGap * counter)); testdrawtext(secondTeamMinuteGoal[i][counter], GREY_TEXT, 240, 150 + (playerYGap * counter)); } } }
Con esto terminamos nuestra aplicación para ver los resultados en vivo de los partidos de la Eurocopa 2024.
Video Explicativo.
No olviden dar like y subscribirse.
Enlace de descarga.
Enlace de descarga con todos los archivos utilizados en este proyecto.
https://mega.nz/file/OBA1URxA#xllk997bwGeilh5YaOV4ubNh6tU8NOX6_tyKHgbutNY
Contacto.
Si quieres que te ayude en algún proyecto:
ignacio.aguilera.contacto@gmail.com