Code:
#include <WiFi.h>
#include <HTTPClient.h>
#include <TFT_eSPI.h>
#include <SPI.h> // Include SPI library
#include <ArduinoJson.h>
#include <time.h>
#include "icons.h" // Include the file that contains the cloud icon
// TFT screen settings
#define TFT_WIDTH 240
#define TFT_HEIGHT 240
#define firstScreenCS 15
#define secondScreenCS 21
#define thirdScreenCS 22
TFT_eSPI tft = TFT_eSPI();
const char* ssid = ""; // Wi-Fi SSID
const char* password = ""; // Wi-Fi password
// WeatherAPI details
const String apiKey = ""; // Replace with your WeatherAPI key
const String city = "Brasov"; // City name (Brasov)
const String weatherUrl = "http://api.weatherapi.com/v1/current.json?key=" + apiKey + "&q=" + city + "&aqi=no";
const char* stockURL = "https://bvb-prices.ro/stock/TVBETETF";
// Time zone offset (in seconds)
// Adjust according to your local time zone. Example: GMT+1 (Europe) is 3600 seconds.
const long gmtOffset_sec = 7200;
// Daylight saving time offset in seconds (0 if not applicable)
const int daylightOffset_sec = 3600;
// Text sizes
const int cityTextSize = 5;
const int tempTextSize = 6;
const int timeTextSize = 6;
const int dateTextSize = 2;
const int stockNameSize = 4;
const int stockPriceSize = 3;
// Cloud icon dimensions
const int CLOUD_ICON_WIDTH = 36;
const int CLOUD_ICON_HEIGHT = 36;
// Clock icon dimensions
const int CLOCK_ICON_WIDTH = 36;
const int CLOCK_ICON_HEIGHT = 36;
// Stock icon dimensions
const int STOCK_ICON_WIDTH = 36;
const int STOCK_ICON_HEIGHT = 36;
// Static Y positions for city and temperature
int cityYPos = 0;
int tempYPos = 0;
int cloudIconYPos = 0; // Y position for the cloud icon
int timeYPos = 0;
int dateYPos = 0;
int clockIconYPos = 0; // Y position for the clock icon
int stockNameYPos = 0;
int stockPriceYPos = 0;
int stockIconYPos = 0; // Y position for the stock icon
void setup() {
Serial.begin(115200);
pinMode(firstScreenCS, OUTPUT);
digitalWrite(firstScreenCS, HIGH);
pinMode(secondScreenCS, OUTPUT);
digitalWrite(secondScreenCS, HIGH);
pinMode(thirdScreenCS, OUTPUT);
digitalWrite(thirdScreenCS, HIGH);
// We need to 'init' both displays
// at the same time. so set both cs pins low
digitalWrite(firstScreenCS, LOW);
digitalWrite(secondScreenCS, LOW);
digitalWrite(thirdScreenCS, LOW);
delay(500);
tft.init();
digitalWrite(firstScreenCS, HIGH);
digitalWrite(secondScreenCS, HIGH);
digitalWrite(thirdScreenCS, HIGH);
delay(500);
digitalWrite(firstScreenCS, LOW);
tft.setRotation(0);
tft.fillScreen(TFT_WHITE); // Set background to white
delay(500);
digitalWrite(firstScreenCS, HIGH);
digitalWrite(secondScreenCS, LOW);
tft.setRotation(0);
tft.fillScreen(TFT_WHITE); // Set background to white
delay(500);
digitalWrite(secondScreenCS, HIGH);
digitalWrite(thirdScreenCS, LOW);
tft.setRotation(0);
tft.fillScreen(TFT_WHITE); // Set background to white
delay(500);
digitalWrite(thirdScreenCS, HIGH);
// Connect to Wi-Fi
connectToWiFi();
// Initialize and configure time
configTime(gmtOffset_sec, daylightOffset_sec, "pool.ntp.org", "time.nist.gov");
// Wait for time to be set
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time");
return;
}
// Calculate the center position for the text and icon
calculateTextPosition();
}
void loop() {
String temperature = fetchWeatherData(); // Fetch weather data
String stockPrice = fetchStockData();
digitalWrite(firstScreenCS, LOW);
// If data is fetched, display city name and temperature
if (temperature != "") {
tft.fillScreen(TFT_WHITE); // Only clear the screen for error message
// Display the cloud icon
displayCloudIcon();
// Display city name and temperature
displayText(tft,"Brasov", cityTextSize, cityYPos);
displayText(tft,temperature.c_str(), tempTextSize, tempYPos);
} else {
// Clear the screen and display error message if data fetch failed
tft.fillScreen(TFT_WHITE); // Only clear the screen for error message
displayText(tft,"Error Fetching Data", 2, cityYPos);
}
delay(500);
digitalWrite(firstScreenCS, HIGH);
delay(1000);
digitalWrite(secondScreenCS, LOW);
displayClockIcon();
displayTime(timeTextSize, dateTextSize); // Display time and date
delay(500);
digitalWrite(secondScreenCS, HIGH);
delay(1000);
digitalWrite(thirdScreenCS, LOW);
if(stockPrice !=""){
tft.fillScreen(TFT_WHITE); // Only clear the screen for error message
displayStockIcon();
displayText(tft,"TVBETETF", stockNameSize, stockNameYPos);
displayText(tft,stockPrice.c_str(), stockPriceSize, stockPriceYPos);
}else {
// Clear the screen and display error message if data fetch failed
tft.fillScreen(TFT_WHITE); // Only clear the screen for error message
displayText(tft,"Error Fetching Data", 2, stockNameYPos);
}
delay(500);
digitalWrite(thirdScreenCS, HIGH);
delay(3000); // Update every 3 seconds
}
void connectToWiFi() {
WiFi.begin(ssid, password);
Serial.print("Connecting to Wi-Fi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nConnected to Wi-Fi");
}
String fetchWeatherData() {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
http.begin(weatherUrl); // API endpoint for fetching weather data
int httpResponseCode = http.GET();
String payload;
if (httpResponseCode > 0) { // Check if the GET request was successful
payload = http.getString();
Serial.println("Weather data fetched successfully");
// Parse the JSON response
DynamicJsonDocument doc(1024);
deserializeJson(doc, payload);
// Extract the temperature from the JSON object
float temp = doc["current"]["temp_c"]; // Current temperature in Celsius
String temperature = String(temp, 1); // Convert temperature to string with 1 decimal place
http.end();
return temperature;
} else {
Serial.print("Error on HTTP request: ");
Serial.println(httpResponseCode);
}
http.end();
} else {
Serial.println("Wi-Fi not connected.");
}
return ""; // Return empty string if there's an error
}
// Function to calculate the center positions for city and temperature with a gap of 5 pixels
void calculateTextPosition() {
int16_t cityTextWidth = tft.textWidth("Brasov") * cityTextSize;
int16_t cityTextHeight = cityTextSize * 8; // Estimated height based on text size
int16_t tempTextWidth = tft.textWidth("00.0") * tempTextSize; // Assuming max temp length like "00.0"
int16_t tempTextHeight = tempTextSize * 8; // Estimated height based on text size'
int16_t timeTextWidth = tft.textWidth("00:00") * timeTextSize; // Assuming "00:00" format for time
int16_t timeTextHeight = timeTextSize * 8; // Estimated height based on text size'
int16_t dateTextWidth = tft.textWidth("00.00.0000") * dateTextSize; // Assuming "00.00.0000" format for date
int16_t dateTextHeight = dateTextSize * 8; // Estimated height based on text size'
int16_t stockTextWidth = tft.textWidth("TVBETETF") * stockNameSize;
int16_t stockTextHeight = stockNameSize * 8; // Estimated height based on text size
int16_t stockPriceTextWidth = tft.textWidth("00.0") * stockPriceSize;
int16_t stockPriceTextHeight = stockPriceSize * 8;
// Calculate center Y positions with a 5px gap between elements
cloudIconYPos = (TFT_HEIGHT - (CLOUD_ICON_HEIGHT + cityTextHeight + tempTextHeight + 10)) / 2; // Top of cloud icon
cityYPos = cloudIconYPos + CLOUD_ICON_HEIGHT + 5; // 5px gap below the cloud icon
tempYPos = cityYPos + cityTextHeight + 5; // 5px gap between city name and temperature
// Calculate center Y positions with a 5px gap between elements
clockIconYPos = (TFT_HEIGHT - (CLOCK_ICON_HEIGHT + timeTextHeight + dateTextHeight + 15)) / 2; // Top of clock icon
timeYPos = clockIconYPos + CLOCK_ICON_HEIGHT + 10; // 5px gap below the clock icon
dateYPos = timeYPos + timeTextHeight + 5; // 5px gap between time and date
// Calculate center Y positions with a 5px gap between elements
stockIconYPos = (TFT_HEIGHT - (STOCK_ICON_HEIGHT + stockTextHeight + stockPriceTextHeight + 15)) / 2; // Top of clock icon
stockNameYPos = stockIconYPos + STOCK_ICON_HEIGHT + 10;
stockPriceYPos = stockNameYPos + stockTextHeight + 5;
}
// Function to display the cloud icon on the screen
void displayCloudIcon() {
// Display the cloud icon at the top of the city name
tft.drawBitmap((TFT_WIDTH - CLOUD_ICON_WIDTH) / 2, cloudIconYPos, cloudIcon, CLOUD_ICON_WIDTH, CLOUD_ICON_HEIGHT, TFT_BLACK);
}
// Function to display the clock icon on the screen
void displayClockIcon() {
tft.drawBitmap((TFT_WIDTH - CLOCK_ICON_WIDTH) / 2, clockIconYPos, clockIcon, CLOCK_ICON_WIDTH, CLOCK_ICON_HEIGHT, TFT_BLACK);
}
// Function to display the cloud icon on the screen
void displayStockIcon() {
// Display the cloud icon at the top of the city name
tft.drawBitmap((TFT_WIDTH - STOCK_ICON_WIDTH) / 2, stockIconYPos, stockIcon, STOCK_ICON_WIDTH, STOCK_ICON_HEIGHT, TFT_BLACK);
}
// Function to display text at a specific position
void displayText(TFT_eSPI &tft,const char* text, int textSize, int yPos) {
tft.setTextSize(textSize);
int16_t textWidth = tft.textWidth(text);
int16_t textHeight = textSize * 8;
// Calculate the X position to center the text horizontally
int16_t x = (TFT_WIDTH - textWidth) / 2;
// Set cursor at the calculated position
tft.setCursor(x, yPos);
tft.setTextColor(TFT_BLACK, TFT_WHITE); // Set text color to black with transparent background
tft.print(text);
}
// Function to display the time and date using calculated positions
void displayTime(int timeSize, int dateSize) {
struct tm timeinfo;
if (getLocalTime(&timeinfo)) {
// Format and display the time using the calculated position
char timeStr[6];
snprintf(timeStr, sizeof(timeStr), "%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min);
displayText(tft,timeStr, timeSize, timeYPos);
// Format and display the date using the calculated position
char dateStr[11];
snprintf(dateStr, sizeof(dateStr), "%02d.%02d.%04d", timeinfo.tm_mday, timeinfo.tm_mon + 1, timeinfo.tm_year + 1900);
displayText(tft,dateStr, dateSize, dateYPos);
} else {
displayText(tft,"Time Error", 2, dateYPos);
}
}
String fetchStockData() {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
http.begin(stockURL);
int httpResponseCode = http.GET();
if (httpResponseCode > 0) {
String payload = http.getString();
Serial.println("Raw HTML data received:");
Serial.println(payload); // Initial HTML for debugging
return payload;
} else {
Serial.println("HTTP request error: " + String(httpResponseCode));
}
http.end();
} else {
Serial.println("WiFi Disconnected");
}
return "";
}```