ESP32 Stock Ticker

esp32

Θέλετε να βλέπετε τις μετοχές σας να πέφτουν οποιαδήποτε στιγμή της ημέρας σε πραγματικό χρόνο;
Με το ESP32 και την ενσωματωμένη OLED τώρα μπορεί να γίνει πραγματικότητα.

Υλικά που θα χρειαστούμε :

  • ESP32 Dev Kit με ενσωματωμένη Οθόνη OLED 0,96″
  • LED Red
  • LED Green
  • Breadboard
  • Jumper Wires

Βήμα 2: Εγκατάσταση του Arduino IDEa

Στη συνέχεια, θα χρειαστούμε το περιβάλλον ανάπτυξης Arduino IDE για να γράψουμε και να “ανεβάσουμε” (upload) τον κώδικα στην πλακέτα ESP32. Αν δεν το έχουμε ήδη στον υπολογιστή μας, μπορούμε να κατεβάσουμε την τελευταία έκδοση από την επίσημη ιστοσελίδα: [Σύνδεσμος προς arduino.cc/downloads]. Επιλέγουμε την έκδοση που είναι συμβατή με το λειτουργικό σύστημα του υπολογιστή μας (Windows, macOS, Linux) και ακολουθούμε τις οδηγίες εγκατάστασης.

Βήμα 3: Ρύθμιση Υποστήριξης ESP32 στο Arduino IDE

Το Arduino IDE, εξ ορισμού, δεν υποστηρίζει τις πλακέτες ESP32. Πρέπει να προσθέσουμε την απαραίτητη υποστήριξη μέσω του Board Manager. Ακολουθούμε αυτά τα βήματα:

  1. Ανοίγουμε το Arduino IDE.
  2. Πηγαίνουμε στο μενού Αρχείο (File) > Προτιμήσεις (Preferences).
  3. Στο πεδίο Additional Boards Manager URLs (Πρόσθετες Διευθύνσεις URL Διαχειριστή Πλακετών), προσθέτουμε την παρακάτω διεύθυνση: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json (Αν υπάρχει ήδη άλλη διεύθυνση, βάζουμε κόμμα , μετά την υπάρχουσα και προσθέτουμε τη νέα).
  4. Πατάμε ΟΚ.
  5. Τώρα, πηγαίνουμε στο μενού Εργαλεία (Tools) > Πλακέτα: (Board:) > Διαχειριστής Πλακετών... (Boards Manager…).
  6. Στο παράθυρο που θα ανοίξει, αναζητούμε “esp32”.
  7. Βρίσκουμε την καταχώρηση “esp32 by Espressif Systems”, την επιλέγουμε και κάνουμε κλικ στο κουμπί Εγκατάσταση (Install).
  8. Περιμένουμε να ολοκληρωθεί η εγκατάσταση.

Πλέον, οι πλακέτες ESP32 είναι διαθέσιμες στο IDE και μπορούμε να επιλέξουμε τη δική μας από το μενού Εργαλεία > Πλακέτα:.

Βήμα 4: Εγκατάσταση Απαραίτητων Βιβλιοθηκών

Για να λειτουργήσει ο κώδικάς μας, χρειαζόμαστε συγκεκριμένες “εργαλειοθήκες” κώδικα, τις βιβλιοθήκες. Θα τις εγκαταστήσουμε μέσω του Library Manager:

  1. Στο Arduino IDE, πηγαίνουμε στο μενού Σκιαγράφημα (Sketch) > Συμπερίληψη Βιβλιοθήκης (Include Library) > Διαχείριση Βιβλιοθηκών... (Manage Libraries…).
  2. Στο παράθυρο Library Manager, αναζητούμε και εγκαθιστούμε μία-μία τις παρακάτω βιβλιοθήκες:
    • ArduinoJson (Χρησιμοποιείται για την ανάλυση των δεδομένων που παίρνουμε από το API).
    • Adafruit GFX (Μια βασική βιβλιοθήκη γραφικών που απαιτείται από την επόμενη).
    • Adafruit SSD1306 (Αυτή είναι η συγκεκριμένη βιβλιοθήκη για τον controller της οθόνης OLED 0.96 ιντσών).
    • (Οι βιβλιοθήκες Wire, WiFi, HTTPClient συνήθως περιλαμβάνονται ήδη στην εγκατάσταση του ESP32 Board Support, αλλά αν αντιμετωπίσουμε πρόβλημα, αναζητούμε και εγκαθιστούμε και αυτές).

Για τις συγκεκριμένες βιβλιοθήκες της Adafruit SSD1306 που χρησιμοποιούνται με ενσωματωμένες οθόνες, συνήθως δεν χρειάζεται να τροποποιήσουμε κάποιο αρχείο ρυθμίσεων. Η αρχικοποίηση στον κώδικα είναι συνήθως αρκετή.

Βήμα 5: Απόκτηση Κλειδιού API από το RapidAPI

Για να λάβουμε τα ζωντανά δεδομένα των μετοχών, ο κώδικας επικοινωνεί με ένα API. Στο παράδειγμά μας, χρησιμοποιούμε ένα API από την πλατφόρα RapidAPI.

  1. Πηγαίνουμε στην ιστοσελίδα του RapidAPI ([Σύνδεσμος προς rapidapi.com]).
  2. Δημιουργούμε έναν λογαριασμό (υπάρχουν συχνά δωρεάν πλάνα χρήσης που είναι επαρκή για αυτό το έργο).
  3. Αναζητούμε το συγκεκριμένο API που χρησιμοποιεί ο κώδικας (Yahoo Finance API). (Πρέπει να βρεις το συγκεκριμένο API στο RapidAPI και ίσως να βάλεις έναν σύνδεσμο εδώ ή να δώσεις οδηγίες πώς να το βρουν).
  4. Εγγραφόμαστε (subscribe) στο δωρεάν πλάνο του API για να αποκτήσουμε το δικό μας προσωπικό apiKey.
  5. ΣΗΜΑΝΤΙΚΟ: Καταγράφουμε προσεκτικά το apiKey που θα μας δοθεί. Θα το χρειαστούμε στον κώδικα.

Ο Κώδικας Βήμα προς Βήμα

Ας αναλύσουμε τον κώδικα που θα ανεβάσουμε στον ESP32 μας. Αντιγράψτε και επικολλήστε τα παρακάτω τμήματα στο σκιαγράφημά σας.

1. Συμπερίληψη Βιβλιοθηκών και Ορισμοί

Αυτό το τμήμα περιλαμβάνει τις βιβλιοθήκες που εγκαταστήσαμε νωρίτερα και ορίζει κάποιες βασικές παραμέτρους για την οθόνη OLED.

#include <Arduino.h>

#include <Wire.h>         // Για επικοινωνία I2C με την οθόνη OLED
#include <WiFi.h>         // Για σύνδεση σε WiFi
#include <HTTPClient.h>   // Για αιτήματα HTTP (λήψη δεδομένων από API)
#include <ArduinoJson.h>  // Για ανάλυση δεδομένων JSON
#include <Adafruit_GFX.h> // Βασική βιβλιοθήκη γραφικών της Adafruit
#include <Adafruit_SSD1306.h> // Βιβλιοθήκη για τον συγκεκριμένο controller της OLED

// Ρυθμίσεις οθόνης OLED
#define SCREEN_WIDTH 128    // Πλάτος οθόνης σε pixels
#define SCREEN_HEIGHT 64   // Ύψος οθόνης σε pixels
#define OLED_RESET    -1   // Reset pin # (-1 if sharing Arduino reset)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // Δημιουργία αντικειμένου οθόνης

Εδώ δηλώνουμε ποιες “εργαλειοθήκες” κώδικα (βιβλιοθήκες) θα χρησιμοποιήσουμε. Η Wire είναι για την επικοινωνία με την οθόνη, η WiFi και η HTTPClient για τη σύνδεση στο internet και τη λήψη δεδομένων, και οι βιβλιοθήκες της Adafruit (GFX, SSD1306) μας επιτρέπουν να “ζωγραφίσουμε” στην οθόνη OLED. Ορίζουμε επίσης τις διαστάσεις της οθόνης μας και δημιουργούμε το αντικείμενο display που θα χρησιμοποιούμε για τις εντολές εμφάνισης.

2. Σύνδεση με WiFi και Λεπτομέρειες API

Εδώ θα βάλουμε τα στοιχεία του δικτύου WiFi μας και τις πληροφορίες για το API που θα χρησιμοποιήσουμε για να πάρουμε τα δεδομένα των μετοχών.

// SSID και password Wi-Fi
const char* ssid = "ΤΟ_ΟΝΟΜΑ_ΤΟΥ_WIFI_ΣΟΥ"; // <-- ΑΛΛΑΞΕ ΑΥΤΟ: Βάζουμε εδώ το όνομα του WiFi μας
const char* password = "ΤΟ_PASSWORD_ΤΟΥ_WIFI_ΣΟΥ"; // <-- ΑΛΛΑΞΕ ΑΥΤΟ: Βάζουμε εδώ τον κωδικό του WiFi μας

// Λεπτομέρειες API (ΒΑΣΙΚΟ: ΧΡΗΣΙΜΟΠΟΙΟΥΜΕ ΤΑ ΔΙΚΑ ΜΑΣ ΣΤΟΙΧΕΙΑ)
const String stockAPI = "https://yahoo-finance15.p.rapidapi.com/api/v1/markets/options/most-active?type=STOCKS"; // Η διεύθυνση του API
const String apiKey = "ΤΟ_ΔΙΚΟ_ΣΟΥ_API_KEY_ΑΠΟ_ΤΟ_RAPIDAPI"; // <-- ΑΛΛΑΞΕ ΑΥΤΟ ΜΕ ΤΟ ΔΙΚΟ ΣΟΥ ΚΛΕΙΔΙ!
const String apiHost = "yahoo-finance15.p.rapidapi.com"; // Ο Host του API - συνήθως δίνεται μαζί με το API key

Εδώ προσαρμόζουμε τον κώδικα στα δικά μας δεδομένα. Αντικαθιστούμε ΤΟ_ΟΝΟΜΑ_ΤΟΥ_WIFI_ΣΟΥ και ΤΟ_PASSWORD_ΤΟΥ_WIFI_ΣΟΥ με τα στοιχεία του δικού μας δικτύου WiFi. Όπως τονίσαμε στο Βήμα 5, είναι απολύτως απαραίτητο να αντικαταστήσουμε το placeholder ΤΟ_ΔΙΚΟ_ΣΟΥ_API_KEY_ΑΠΟ_ΤΟ_RAPIDAPI με το προσωπικό κλειδί API που αποκτήσαμε από το RapidAPI.

3. Πληροφορίες Χαρτοφυλακίου και Εναλλαγή Οθονών

Εδώ ορίζουμε ποιες μετοχές θέλουμε να παρακολουθούμε και πόσες μονάδες έχουμε από την καθεμία (για τον υπολογισμό της αξίας). Ρυθμίζουμε επίσης πόσο συχνά θα αλλάζει η οθόνη μεταξύ των μετοχών.

// Πληροφορίες Χαρτοφυλακίου (Προσαρμόζουμε στις δικές μας μετοχές)
const float numberOfAMDStocks = 310; // Αριθμός μετοχών AMD
const int numberOfINTCStocks = 100; // Αριθμός μετοχών Intel
const int numberOfNVDAStocks = 50; // Αριθμός μετοχών Nvidia

// Μεταβλητές για εναλλαγή οθονών
int currentScreen = 0; // Ξεκινάμε από την πρώτη οθόνη (0)
unsigned long lastSwitchTime = 0; // Μεταβλητή για να παρακολουθούμε τον χρόνο
const unsigned long screenInterval = 30000; // Διάρκεια εμφάνισης κάθε οθόνης σε χιλιοστά του δευτερολέπτου (30 δευτερόλεπτα)

Στο τμήμα “Πληροφορίες Χαρτοφυλακίου”, μπορούμε να αλλάξουμε τα σύμβολα των μετοχών (“AMD”, “INTC”, “NVDA”) και τους αριθμούς (numberOf...Stocks) για να παρακολουθούμε τις δικές μας μετοχές. Οι μεταβλητές για την εναλλαγή οθονών (currentScreen, lastSwitchTime, screenInterval) θα χρησιμοποιηθούν αργότερα στη συνάρτηση loop() για να διαχειριστούμε την εμφάνιση κάθε μετοχής για συγκεκριμένο χρονικό διάστημα.

4. Η συνάρτηση setup()

Αυτή η συνάρτηση είναι η πρώτη που εκτελείται και τρέχει μόνο μία φορά όταν ο ESP32 ξεκινάει. Εδώ κάνουμε όλες τις αρχικές ρυθμίσεις.

void setup() {
  // Εκκίνηση σειριακής επικοινωνίας (για debugging στον Serial Monitor)
  Serial.begin(115200);

  // Αρχικοποίηση οθόνης OLED με διεύθυνση I2C 0x3C
  // Η διεύθυνση 0x3C είναι η πιο συνηθισμένη για αυτές τις οθόνες
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("SSD1306 allocation failed");
    for (;;); // Αν η αρχικοποίηση αποτύχει, σταματάμε εδώ
  }

  // Καθαρισμός buffer οθόνης και εμφάνιση
  display.clearDisplay();
  display.display();

  // Εμφάνιση μηνύματος εκκίνησης στην οθόνη
  display.setTextSize(1);      // Μέγεθος κειμένου
  display.setTextColor(WHITE); // Χρώμα κειμένου
  display.setCursor(0, 0);     // Θέση εκκίνησης κειμένου
  display.println("Connecting to WiFi..."); // Εκτύπωση μηνύματος
  display.display(); // Εμφάνιση στην οθόνη

  // Σύνδεση σε Wi-Fi
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi");
  // Προσθέτουμε ένα timeout για τη σύνδεση WiFi για να μην κολλήσει επ' άπειρον
  long wifiConnectStart = millis();
  while (WiFi.status() != WL_CONNECTED && millis() - wifiConnectStart < 30000) { // Δοκιμάζουμε για 30 δευτερόλεπτα
    delay(500); // Περιμένουμε μισό δευτερόλεπτο
    Serial.print("."); // Εκτυπώνουμε μια τελεία στο Serial Monitor όσο περιμένουμε
  }
  Serial.println(); // Νέα γραμμή

  if(WiFi.status() == WL_CONNECTED){ // Αν συνδεθήκαμε επιτυχώς
    Serial.println("Connected to WiFi"); // Εκτύπωση επιτυχίας στο Serial Monitor
    // Εμφάνιση κατάστασης σύνδεσης WiFi στην οθόνη OLED
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println("WiFi Connected");
    display.display();

    // Λήψη πληροφοριών μετοχών αμέσως μετά τη σύνδεση WiFi
    fetchAndDisplayStockInfo(); // Καλείται η συνάρτηση για να πάρουμε τα πρώτα δεδομένα

  } else { // Αν η σύνδεση απέτυχε
    Serial.println("WiFi Connection Failed."); // Εκτύπωση σφάλματος στο Serial Monitor
    // Εμφάνιση σφάλματος σύνδεσης WiFi στην οθόνη OLED
    display.clearDisplay();
    display.setCursor(0, 0);
    display.println("WiFi Failed.");
    display.println("Check credentials.");
    display.display();
  }
}

Επεξήγηση: Στο setup, αρχικοποιούμε τη σειριακή επικοινωνία (που μας βοηθάει στο debugging βλέποντας μηνύματα στον υπολογιστή), ρυθμίζουμε και αρχικοποιούμε την οθόνη OLED. Ελέγχουμε αν η οθόνη βρεθεί στην τυπική διεύθυνση I2C (0x3C). Στη συνέχεια, προσπαθούμε να συνδεθούμε στο WiFi χρησιμοποιώντας τα στοιχεία που δώσαμε, με ένα χρονικό όριο (timeout) 30 δευτερολέπτων για να μην “κολλήσει” η πλακέτα αν δεν βρει δίκτυο. Αν η σύνδεση είναι επιτυχής, εμφανίζουμε μήνυμα στην οθόνη και καλούμε αμέσως την WorkspaceAndDisplayStockInfo για να εμφανίσουμε τα πρώτα δεδομένα. Αν αποτύχει η σύνδεση, εμφανίζουμε σχετικό μήνυμα σφάλματος στην οθόνη.

5. Η συνάρτηση loop()

Αυτή η συνάρτηση εκτελείται συνεχώς μετά το setup. Ο ρόλος της εδώ είναι να ελέγχει πότε πρέπει να αλλάξει η οθόνη στην επόμενη μετοχή και να επικαιροποιήσει τα δεδομένα από το API.

void loop() {
  // Εναλλαγή οθονών κάθε `screenInterval` χιλιοστά του δευτερολέπτου
  unsigned long currentMillis = millis(); // Παίρνουμε τον τρέχοντα χρόνο σε χιλιοστά του δευτερολέπτου
  if (currentMillis - lastSwitchTime >= screenInterval) { // Ελέγχουμε αν πέρασε ο χρόνος για αλλαγή
    lastSwitchTime = currentMillis; // Ενημερώνουμε τον χρόνο της τελευταίας αλλαγής

    // Αλλάζουμε οθόνη και λαμβάνουμε νέα δεδομένα μόνο αν το WiFi είναι συνδεδεμένο
    if(WiFi.status() == WL_CONNECTED){
      currentScreen = (currentScreen + 1) % 3; // Πάμε στην επόμενη οθόνη (0 -> 1 -> 2 -> 0 ...) - Το % 3 δημιουργεί τον κύκλο για τις 3 μετοχές μας
      fetchAndDisplayStockInfo(); // Καλούμε τη συνάρτηση για να λάβουμε και να εμφανίσουμε νέα δεδομένα για την επόμενη οθόνη
    } else {
      // Αν το WiFi χάθηκε, προσπαθούμε να συνδεθούμε ξανά
      Serial.println("Attempting to reconnect to WiFi...");
      display.clearDisplay(); display.setCursor(0,0); display.setTextSize(1);
      display.println("Reconnecting..."); display.display();
      WiFi.begin(ssid, password);
      // Προσθέτουμε μια μικρή καθυστέρηση για να δώσουμε χρόνο στην προσπάθεια σύνδεσης
      delay(5000); // Περιμένουμε 5 δευτερόλεπτα πριν τον επόμενο έλεγχο στο loop
    }
  }
  // Δεν χρειάζεται άλλο delay() εδώ, καθώς η fetchAndDisplayStockInfo() και το delay() στην αποτυχημένη σύνδεση διαχειρίζονται τον χρόνο.
  // Το loop τρέχει πολύ γρήγορα αν δεν γίνει αλλαγή οθόνης ή αποτύχει η σύνδεση/λήψη δεδομένων.
}

Επεξήγηση: Η συνάρτηση loop είναι ο “χτύπος” του προγράμματος. Ελέγχει συνεχώς αν έχει περάσει ο χρόνος που έχουμε ορίσει (screenInterval) από την τελευταία φορά που αλλάξαμε οθόνη. Όταν περάσει ο χρόνος, ενημερώνει τον χρονομετρητή, αυξάνει την τιμή της μεταβλητής currentScreen για να δείξει την επόμενη μετοχή στον κύκλο (AMD, INTC, NVDA) και καλεί τη συνάρτηση WorkspaceAndDisplayStockInfo() για να επικαιροποιήσει τα δεδομένα και να τα εμφανίσει στην οθόνη. Προσθέσαμε και έναν έλεγχο: αν χαθεί η σύνδεση WiFi, εμφανίζει σχετικό μήνυμα και προσπαθεί να συνδεθεί ξανά.

6. Η συνάρτηση WorkspaceAndDisplayStockInfo()

Αυτή είναι η πιο σύνθετη συνάρτηση και κάνει την κύρια “δουλειά” της λήψης και εμφάνισης των δεδομένων.

void fetchAndDisplayStockInfo() {
  if (WiFi.status() == WL_CONNECTED) { // Ελέγχουμε ξανά αν το WiFi είναι συνδεδεμένο πριν κάνουμε αίτημα
    HTTPClient http; // Δημιουργούμε αντικείμενο HTTPClient

    http.begin(stockAPI); // Θέτουμε τη διεύθυνση του API
    http.addHeader("x-rapidapi-key", apiKey); // Προσθέτουμε το header με το API key μας
    http.addHeader("x-rapidapi-host", apiHost); // Προσθέτουμε το header με τον API host

    int httpResponseCode = http.GET(); // Εκτελούμε το αίτημα GET και παίρνουμε τον κωδικό απάντησης
    Serial.print("HTTP Response Code: ");
    Serial.println(httpResponseCode); // Εκτυπώνουμε τον κωδικό απάντησης στο Serial Monitor

    if (httpResponseCode > 0) { // Αν η απάντηση είναι επιτυχής (π.χ. 200 OK)
      String payload = http.getString(); // Λαμβάνουμε τα δεδομένα ως String
      Serial.println("Payload Received:");
      Serial.println(payload); // Εκτυπώνουμε τα δεδομένα στο Serial Monitor

      // Δημιουργία buffer για το JSON document (Προσαρμόστε τη χωρητικότητα αν χρειάζεται, δείτε ArduinoJson Assistant)
      const size_t capacity = JSON_ARRAY_SIZE(20) + 20 * JSON_OBJECT_SIZE(2) + 1024; // Εκτιμώμενη χωρητικότητα
      DynamicJsonDocument doc(capacity); // Δημιουργούμε ένα DynamicJsonDocument

      // Δημιουργία φίλτρου για να αναλύονται μόνο τα απαραίτητα πεδία (Εξοικονομεί μνήμη)
      StaticJsonDocument filter; // Προσαρμόστε το μέγεθος αν αλλάξετε το φίλτρο
      filter["body"][0]["symbol"] = true;
      filter["body"][0]["lastPrice"] = true;
      filter["body"][0]["priceChange"] = true;
      filter["body"][0]["percentChange"] = true;

      // Ανάλυση του JSON payload με το φίλτρο
      DeserializationError error = deserializeJson(doc, payload, DeserializationOption::Filter(filter));
      if (error) { // Αν υπάρξει σφάλμα στην ανάλυση JSON
        Serial.print("JSON deserialization failed: ");
        Serial.println(error.c_str()); // Εκτυπώνουμε το σφάλμα
        // Προαιρετικά: Εμφάνιση σφάλματος στην οθόνη OLED
        display.clearDisplay(); display.setCursor(0,0); display.setTextSize(1);
        display.println("JSON Error"); display.println(error.c_str()); display.display();
        return; // Βγαίνουμε από τη συνάρτηση
      }

      // Μεταβλητές για να αποθηκεύσουμε τα δεδομένα των μετοχών που μας ενδιαφέρουν
      float lastAMDPrice = 0.0;
      float lastINTCPrice = 0.0;
      float lastNVDAPrice = 0.0;
      float amdValue = 0.0; // Αξία χαρτοφυλακίου AMD
      float intcValue = 0.0; // Αξία χαρτοφυλακίου INTC
      float nvdaValue = 0.0; // Αξία χαρτοφυλακίου NVDA
      String amdChangeText = "", intcChangeText = "", nvdaChangeText = ""; // Κείμενο αλλαγής τιμής και ποσοστού

      // Διάσχιση του JSON array "body" για εύρεση των σχετικών μετοχών
      JsonArray body = doc["body"]; // Παίρνουμε το array με τις μετοχές
      for (JsonObject stock : body) { // Για κάθε αντικείμενο (μετοχή) μέσα στο array
        const char* symbol = stock["symbol"]; // Λαμβάνουμε το σύμβολο της μετοχής
        const char* lastPrice = stock["lastPrice"]; // Λαμβάνουμε την τελευταία τιμή
        const char* priceChange = stock["priceChange"]; // Λαμβάνουμε την αλλαγή τιμής (σε αξία)
        const char* percentChange = stock["percentChange"]; // Λαμβάνουμε την ποσοστιαία αλλαγή

        // Προσθέτουμε ελέγχους αν τα δεδομένα υπάρχουν πριν τα χρησιμοποιήσουμε
        if (!symbol || !lastPrice || !priceChange || !percentChange) {
          Serial.println("Skipping incomplete stock data");
          continue; // Αν λείπουν δεδομένα, παραλείπουμε αυτό το αντικείμενο
        }

        Serial.print("Processing stock: "); Serial.println(symbol); // Εκτυπώνουμε ποια μετοχή επεξεργαζόμαστε

        if (String(symbol) == "AMD") { // Αν το σύμβολο είναι AMD
          lastAMDPrice = atof(lastPrice); // Μετατρέπουμε την τιμή από κείμενο σε αριθμό float
          amdValue = numberOfAMDStocks * lastAMDPrice; // Υπολογίζουμε την αξία του χαρτοφυλακίου μας σε AMD
           if (priceChange && percentChange) {
               amdChangeText = String(priceChange) + " (" + String(percentChange) + ")"; // Δημιουργούμε το κείμενο αλλαγής (π.χ. "+1.50 (2.1%)")
            } else {
               amdChangeText = "N/A"; // Αν λείπουν τα στοιχεία αλλαγής
            }
          Serial.print("AMD Price: $"); Serial.println(lastAMDPrice, 2); // Εκτυπώνουμε στο Serial Monitor με 2 δεκαδικά
          Serial.print("AMD Value: $"); Serial.println(amdValue, 2);
        } else if (String(symbol) == "INTC") { // Αν το σύμβολο είναι INTC
          lastINTCPrice = atof(lastPrice);
          intcValue = numberOfINTCStocks * lastINTCPrice;
           if (priceChange && percentChange) {
               intcChangeText = String(priceChange) + " (" + String(percentChange) + ")";
            } else {
               intcChangeText = "N/A";
            }
          Serial.print("INTC Price: $"); Serial.println(lastINTCPrice, 2);
          Serial.print("INTC Value: $"); Serial.println(intcValue, 2);
        } else if (String(symbol) == "NVDA") { // Αν το σύμβολο είναι NVDA
          lastNVDAPrice = atof(lastPrice);
          nvdaValue = numberOfNVDAStocks * lastNVDAPrice;
            if (priceChange && percentChange) {
               nvdaChangeText = String(priceChange) + " (" + String(percentChange) + ")";
            } else {
               nvdaChangeText = "N/A";
            }
          Serial.print("NVDA Price: $"); Serial.println(lastNVDAPrice, 2);
          Serial.print("NVDA Value: $"); Serial.println(nvdaValue, 2);
        }
      }

      // Καθαρισμός οθόνης πριν την εμφάνιση των νέων δεδομένων
      display.clearDisplay();

      // Εμφάνιση πληροφοριών ανάλογα με την τρέχουσα οθόνη (currentScreen)
      display.setTextColor(WHITE); // Ρυθμίζουμε το χρώμα κειμένου σε λευκό (για OLED)

      if (currentScreen == 0) { // Αν είναι η 1η οθόνη (AMD)
        // Εμφανίζουμε πληροφορίες AMD
        display.setCursor(0, 0); display.setTextSize(1); display.print("AMD: "); display.println(amdChangeText);
        display.setCursor(0, 20); display.setTextSize(2); display.print("$"); display.println(lastAMDPrice, 2);
        display.setCursor(0, 50); display.setTextSize(1); display.print("Value: $"); display.println(amdValue, 2);
      } else if (currentScreen == 1) { // Αν είναι η 2η οθόνη (INTC)
        // Εμφανίζουμε πληροφορίες Intel
        display.setCursor(0, 0); display.setTextSize(1); display.print("INTC: "); display.println(intcChangeText);
        display.setCursor(0, 20); display.setTextSize(2); display.print("$"); display.println(lastINTCPrice, 2);
        display.setCursor(0, 50); display.setTextSize(1); display.print("Value: $"); display.println(intcValue, 2);
      } else if (currentScreen == 2) { // Αν είναι η 3η οθόνη (NVDA)
        // Εμφανίζουμε πληροφορίες Nvidia
        display.setCursor(0, 0); display.setTextSize(1); display.print("NVDA: "); display.println(nvdaChangeText);
        display.setCursor(0, 20); display.setTextSize(2); display.print("$"); display.println(lastNVDAPrice, 2);
        display.setCursor(0, 50); display.setTextSize(1); display.print("Value: $"); display.println(nvdaValue, 2);
      }

      // Ενημέρωση της οθόνης για να εμφανιστούν οι αλλαγές
      display.display();

    } else { // Αν υπάρξει σφάλμα στην απάντηση HTTP (κωδικός <= 0)
      Serial.print("Error in fetching stock data, HTTP response code: ");
      Serial.println(httpResponseCode); // Εκτυπώνουμε το σφάλμα στο Serial Monitor
      // Εμφάνιση σφάλματος στην οθόνη OLED
      display.clearDisplay(); display.setCursor(0,0); display.setTextSize(1);
      display.println("HTTP Error:"); display.println(httpResponseCode); display.display();
    }

    http.end(); // Αποδέσμευση πόρων HTTPClient
  } else { // Αν το WiFi δεν είναι συνδεδεμένο κατά την κλήση της συνάρτησης
    Serial.println("WiFi not connected"); // Εκτυπώνουμε μήνυμα στο Serial Monitor
    // Εμφάνιση μηνύματος στην οθόνη OLED
    display.clearDisplay(); display.setCursor(0,0); display.setTextSize(1);
    display.println("WiFi Disconnected"); display.display();
  }
}

Επεξήγηση: Αυτή είναι η πιο σύνθετη συνάρτηση και κάνει την κύρια “δουλειά” του ticker. Ξεκινάμε ελέγχοντας αν το WiFi είναι συνδεδεμένο. Μετά, δημιουργούμε ένα αντικείμενο HTTPClient για να κάνουμε αίτημα στο API, προσθέτουμε τα απαραίτητα headers (το κλειδί API και τον Host) και στέλνουμε το αίτημα (http.GET()). Ελέγχουμε τον κωδικό απάντησης για να δούμε αν ήταν επιτυχής. Αν ναι, λαμβάνουμε τα δεδομένα (payload), τα οποία είναι σε μορφή JSON. Χρησιμοποιούμε τη βιβλιοθήκη ArduinoJson για να αναλύσουμε αυτά τα δεδομένα, χρησιμοποιώντας ένα φίλτρο για να διαβάσουμε μόνο τα πεδία που χρειαζόμαστε (σύμβολο, τιμή, αλλαγές), κάτι που είναι σημαντικό για την περιορισμένη μνήμη του μικροελεγκτή. Διασχίζουμε τα αναλυμένα δεδομένα, βρίσκουμε τις μετοχές που μας ενδιαφέρουν (AMD, INTC, NVDA), μετατρέπουμε τις τιμές σε αριθμούς και υπολογίζουμε την αξία του χαρτοφυλακίου μας. Στη συνέχεια, καθαρίζουμε την οθόνη και εμφανίζουμε τις πληροφορίες για την τρέχουσα μετοχή (αυτή που έχει επιλέξει η συνάρτηση loop) χρησιμοποιώντας τις συναρτήσεις της βιβλιοθήκης Adafruit για τη θέση του κειμένου, το μέγεθος και το περιεχόμενο. Υπάρχει και διαχείριση σφαλμάτων αν η λήψη δεδομένων αποτύχει ή αν χαθεί η σύνδεση WiFi.

1 thoughts on “ESP32 Stock Ticker

Αφήστε μια απάντηση

Η ηλ. διεύθυνση σας δεν δημοσιεύεται. Τα υποχρεωτικά πεδία σημειώνονται με *