

/*
    * Fetch BTC price from coinmarketcap API, and display on 8x7segment display.
    * 
    * code id based on Hector de Isidro worke: https://github.com/hrules6872
    * 
      TLSv1.2 is supported since version 2.4.0-rc1
    Created by Nimrod Galor, 2019.

    Load it as if loading it to   NodeMCU 0.9 (ESP-12 Module)

    JD additional comments 08/02/21:
    
    Max allowed is 30 calls per minute which is plenty !

    I have taken the code above by Nimrod Galor which was meant to run a large LED display and modified it to extract a set of currently 9 coins from Coinmarket Cap and display their values in dollars.
    Each one updates approximately every 30 seconds so the whole set update roughly every 4 to 5 minutes.
    It now runs on a        ESP8266 ESP-12F Wifi NODEMCU Wemos Development Board CP2102 +0.96" OLED          This board has an integrated 0.96" OLEd screen.
    
    
*/

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
//#include <LedControl.h>
#include <Wire.h>
#include "SSD1306.h"

#ifndef STASSID
#define STASSID "YOUR_NETWORK_ADDRESS"
#define STAPSK  "YOUR_PASSWORD"
#endif

//create display(Adr, SDA-pin, SCL-pin)
SSD1306 display(0x3c, 5, 4); //GPIO 5 = D1, GPIO 4 = D2
//SSD1306  display(0x3c, 5 /*D1*/, 4 /*D2*/);

int DISPLAY_WIDTH = 128;
int DISPLAY_HEIGHT = 64;


const char* ssid = STASSID;
const char* password = STAPSK;

const String API_KEY = "d9fabf7e-573b-4e48-8bf7-c25294a9ff82";

char* SYMBOL = "BTC";
const char* CONVERT_TO = "USD";

int currency;
int currency1value;   // BTC is best shown as an integer
int currency2value;   // ETH is best shown as an integer
float currency3value;
float currency4value;
float currency5value;
float currency6value;
float currency7value;
int currency8value;   // COMP is best shown as an integer
float currency9value;
float currency10value;

float price;


//const long DEFAULT_DELAY = 60 * 1000 * 5; // wait 5 minutes between API request;
const long DEFAULT_DELAY = 30 * 1000; // wait 30 sec between API request;

const char* host = "pro-api.coinmarketcap.com";
const int httpsPort = 443;

// Use web browser to view and copy
// SHA1 fingerprint of the certificate
const char fingerprint[] PROGMEM = "335b4fc7b2e210256ed6f2f900744ea21f436195";

// Use WiFiClientSecure class to create TLS connection
  WiFiClientSecure client;

/* 
* Create a new controller 
* Params :*/
//int dataPin = D5;    //The pin on the Arduino where data gets shifted out
//int csPin = D6;      //The pin for selecting the device when data is to be sent
//int clockPin = D7;   //The pin for the clock
//int numDevices = 8; //The maximum number of devices that can be controlled

//LedControl lc=LedControl(dataPin, clockPin, csPin, numDevices);

void setup() {
  Serial.begin(115200);
  Serial.println();
  Serial.print("connecting to ");
  Serial.println(ssid);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());


  //OLED Display
    display.init();
  //display.flipScreenVertically();
  
  
  display.clear();
  display.setFont(ArialMT_Plain_24);
  display.drawString(0, 0, "STARTING");
  display.display();


// init LedControl 
//Serial.print("index: ");
//Serial.println(lc.getDeviceCount());
//  for(int index=0;index<lc.getDeviceCount();index++) {
//      lc.shutdown(index,false);
      /* Set the brightness to a medium values */
//      lc.setIntensity(index,8);
      /* and clear the display */
//      lc.clearDisplay(index);
//  }
//   printPrice(99999999);

   
}


void loop() {
  Serial.print("connecting to ");
  Serial.println(host);

  Serial.printf("Using fingerprint '%s'\n", fingerprint);
  client.setFingerprint(fingerprint);

  if (!client.connect(host, httpsPort)) {
    Serial.println("connection failed");
    return;
  }

  String url = "/v1/cryptocurrency/quotes/latest?CMC_PRO_API_KEY=" + API_KEY + "&symbol=" + SYMBOL + "&convert=" + CONVERT_TO;
  Serial.print("requesting URL: ");
  Serial.println(url);

  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "User-Agent: BuildFailureDetectorESP8266\r\n" +
               "Connection: close\r\n\r\n");

  Serial.println("request sent");

  // check HTTP response
  char httpStatus[32] = {0};
  client.readBytesUntil('\r', httpStatus, sizeof(httpStatus));
  if (strcmp(httpStatus, "HTTP/1.1 200 OK") != 0) {
    Serial.print("Unexpected response: ");
    Serial.println(httpStatus);
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  currency = currency + 1;
  if(currency == 10){ currency = 1; }
  if (currency == 1){ SYMBOL = "BTC"; }
  if (currency == 2){ SYMBOL = "ETH"; }
  if (currency == 3){ SYMBOL = "ADA"; }
  if (currency == 4){ SYMBOL = "DOT"; }
  if (currency == 5){ SYMBOL = "XTZ"; }
  if (currency == 6){ SYMBOL = "AVE"; }
  if (currency == 7){ SYMBOL = "THETA"; }
  if (currency == 8){ SYMBOL = "COMP"; }
  if (currency == 9){ SYMBOL = "AVAX"; }
  //if (currency == 10){ SYMBOL = "---"; }



//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    
    delay();
    return;
  }

  
  // skip HTTP headers
  while (client.connected()) {
    String line = client.readStringUntil('\n');
    Serial.println(line);
    if (line == "\r") {
      break;
    }
  }

  // skip content length
  if (client.connected()) {
    String line = client.readStringUntil('\n');
    Serial.println(line);
  }

  // get response
  String response = "";
  while (client.connected()) {
    String line = client.readStringUntil('\n');
    Serial.println(line);
    line.trim();
    if (line != "\r") {
      response += line;
    }
  }

  client.stop();

  // parse response
  DynamicJsonDocument jsonDocument(2024);
  DeserializationError error = deserializeJson(jsonDocument, response);
  if (error) {
    Serial.println("Deserialization failed");
     
     switch (error.code()) {
      case DeserializationError::Ok:
          Serial.print(F("Deserialization succeeded"));
          break;
      case DeserializationError::InvalidInput:
          Serial.print(F("Invalid input!"));
          break;
      case DeserializationError::NoMemory:
          Serial.print(F("Not enough memory"));
          Serial.println("doc capacity: ");
          Serial.print(jsonDocument.capacity());
          break;
      default:
          Serial.print(F("Deserialization failed"));
          break;
    }
     
    delay();
    return;
  }
  JsonObject root = jsonDocument.as<JsonObject>();

  // check API status
  JsonObject status = root["status"];
  int statusErrorCode = status["error_code"];
  if (statusErrorCode != 0) {
    String statusErrorMessage = status["error_message"];
    Serial.print("Error: ");
    Serial.println(statusErrorMessage);
    delay();
  }

  JsonObject coin = root["data"][SYMBOL];
  String name = coin["name"];
  String lastUpdated = coin["last_updated"];
  Serial.println("Name: " + name);
  Serial.println("Last updated: " + lastUpdated);

  JsonObject quote = coin["quote"][CONVERT_TO];
  //float price = quote["price"];
  price = quote["price"];
  Serial.print("Price: $");
  Serial.println(price, 2);

  //printPrice((int)price);

  printPrice();



  
  delay();




  
}   // End of main void loop





//void printPrice(int price){
void printPrice(){
  // reset
 // for(int index=0;index<lc.getDeviceCount();index++) {
 //   lc.clearDisplay(index);
 // }

 // int index = floor((8-sizeof(price)) /2);
 // while(price > 0){
 //   lc.setDigit(0, index, price%10, false);
 //   price = price/10;
 //   index++;
 // }

 Serial.print("PRICE= ");
 Serial.println(price);

  if (currency == 1){ currency1value = (int)price; }     // BTC is an integer else the float version of the value would take up too much of the screen
  if (currency == 2){ currency2value = (int)price; }     // ETH is an integer else the float version of the value would take up too much of the screen
  if (currency == 3){ currency3value = price; }
  if (currency == 4){ currency4value = price; }
  if (currency == 5){ currency5value = price; }
  if (currency == 6){ currency6value = price; }
  if (currency == 7){ currency7value = price; }
  if (currency == 8){ currency8value = (int)price; }      // COMP is an integer else the float version of the value would take up too much of the screen
  if (currency == 9){ currency9value = price; }
  if (currency == 10){ currency10value = price; }





 updatethescreen();

     // Produces a currency value of 1 to 5 in sequence
  currency = currency + 1;
  if(currency == 10){ currency = 1; }
  if (currency == 1){ SYMBOL = "BTC"; }
  if (currency == 2){ SYMBOL = "ETH"; }
  if (currency == 3){ SYMBOL = "ADA"; }
  if (currency == 4){ SYMBOL = "DOT"; }
  if (currency == 5){ SYMBOL = "XTZ"; }
  if (currency == 6){ SYMBOL = "AAVE"; }
  if (currency == 7){ SYMBOL = "THETA"; }
  if (currency == 8){ SYMBOL = "COMP"; }
  if (currency == 9){ SYMBOL = "AVAX"; }
  //if (currency == 10){ SYMBOL = "---"; }
  
  
}

  
void delay() {
  Serial.println("");
  Serial.println("Keep calm and hodl!");
  //delay(DEFAULT_DELAY);
  int del = DEFAULT_DELAY / 12;
  display.drawLine(0, 0, 12, 0);
  display.drawLine(0, 63, 12, 63);
  display.display();
  delay(del);
  display.drawLine(13, 0, 24, 0);
  display.drawLine(13, 63, 24, 63);
  display.display();
  delay(del);
  display.drawLine(25, 0, 36, 0);
  display.drawLine(25, 63, 36, 63);
  display.display();
  delay(del);
  display.drawLine(37, 0, 48, 0);
  display.drawLine(37, 63, 48, 63);
  display.display();
  delay(del);
  display.drawLine(49, 0, 60, 0);
  display.drawLine(49, 63, 60, 63);
  display.display();
  delay(del);
  display.drawLine(61, 0, 72, 0);
  display.drawLine(61, 63, 72, 63);
  display.display();
  delay(del);
  display.drawLine(73, 0, 84, 0);
  display.drawLine(73, 63, 84, 63);
  display.display();
  delay(del);
  display.drawLine(85, 0, 96, 0);
  display.drawLine(85, 63, 96, 63);
  display.display();
  delay(del);
  display.drawLine(97, 0, 108, 0);
  display.drawLine(97, 63, 108, 63);
  display.display();
  delay(del);
  display.drawLine(109, 0, 120, 0);
  display.drawLine(109, 63, 120, 63);
  display.display();
  delay(del);
  display.drawLine(121, 0, 127, 0);
  display.drawLine(121, 63, 127, 63);
  display.display();


}




void updatethescreen(){

  // Flash latest value up in large font for a few seconds
                  display.clear();
                  display.setFont(ArialMT_Plain_24);
                  display.drawString(15, 0, SYMBOL);
                  display.drawString(15, 30, String(price));
                  display.drawLine(8, 0, 120, 0);  //top line
                  display.drawLine(8, 63, 120, 63);  //bottom line
                  display.drawLine(8, 0, 8, 63);  //left line
                  display.drawLine(120, 0, 120, 63);  //right line
                  
                  display.display();
                  delay(2500);
                  
  // Close this large display and then display the listing of all the coins being followed.               
                  display.clear();
                  display.setFont(ArialMT_Plain_10);

                  display.drawString(0, 0, "BTC");  // Label
                  display.drawString(0, 13, "ETH");  // Label
                  display.drawString(0, 26, "ADA");  // Label
                  display.drawString(0, 39, "DOT");  // Label
                  display.drawString(0, 52, "XTZ");  // Label
                   
                  
                  display.drawString(27, 0, String(currency1value));
                  display.drawString(27, 13, String(currency2value));
                  display.drawString(27, 26, String(currency3value));
                  display.drawString(27, 39, String(currency4value));
                  display.drawString(27, 52, String(currency5value));
                  

                  display.drawString(66, 0, "AAVE");  // Label
                  display.drawString(66, 13, "THET");  // Label
                  display.drawString(66, 26, "COMP");  // Label
                  display.drawString(66, 39, "AVAX");  // Label
                  //display.drawString(66, 52, "---");  // Label
                   
                  
                  display.drawString(100, 0, String(currency6value));
                  display.drawString(100, 13, String(currency7value));
                  display.drawString(100, 26, String(currency8value));
                  display.drawString(100, 39, String(currency9value));
                  //display.drawString(100, 52, String(currency10value));
                  display.display();                  



} // end of void updatethescreen
