Untitled

 avatar
unknown
plain_text
a year ago
12 kB
43
No Index
#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 "";
}
Editor is loading...
Leave a Comment