/* Cryptocurrency tracker example for e-radionica.com Inkplate 6 For this example you will need only USB cable and Inkplate 6. Select "Inkplate 6(ESP32)" from Tools -> Board menu. Don't have "Inkplate 6(ESP32)" option? Follow our tutorial and add it: https://e-radionica.com/en/blog/add-inkplate-6-to-arduino-ide/ This example will show you how you can use Inkplate 6 to display API data, e.g. coingecko api IMPORTANT: Make sure to change your timezone and wifi credentials below Also have ArduinoJSON installed in your Arduino libraries Want to learn more about Inkplate? Visit www.inkplate.io Looking to get support? Write on our forums: http://forum.e-radionica.com/en/ 28 July 2020 by e-radionica.com */ // ---------- CHANGE HERE -------------: // Adjust your time zone int timeZone = 2; // Put in your ssid and password char *ssid = ""; char *pass = ""; // OPTIONAL: // change to a different currency char *currency = "bitcoin"; char *currencyAbbr = "BTC"; // ---------------------------------- // Include Inkplate library to the sketch #include "Inkplate.h" // Include fonts used #include "Fonts/Roboto_Light_160.h" #include "Fonts/Roboto_Light_40.h" #include "Fonts/Roboto_Light_36.h" // Our networking functions, declared in Network.cpp #include "Network.h" // create object with all networking functions Network network; // create Inkplate display(INKPLATE_3BIT); // Delay between API calls #define DELAY_MS 5000 // Variable for counting partial refreshes long refreshes = 0; // Constant to determine when to full update const int fullRefresh = 20; // Used for storing raw price values float data[64]; // Used to simplify UI design struct textElement { int x; int y; const GFXfont *font; char *text; char align; }; // Variables for storing all displayed data as char arrays char date[64]; char fromToDate[64]; char dates[8 * 8]; char prices[16 * 16]; char current[16]; char minimum[16]; char maximum[16]; // All months in a year, for finding current date char *months[] = { "Jan" "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", }; // Out UI elements data textElement elements[] = { {50, 130, &Roboto_Light_160, currencyAbbr, 0}, {390, 80, &Roboto_Light_40, date, 0}, {190, 185, &Roboto_Light_40, fromToDate, 0}, {570, 140, &Roboto_Light_40, "Current price:", 0}, {790, 190, &Roboto_Light_40, current, 1}, {630, 275, &Roboto_Light_40, "Minimum", 0}, {790, 320, &Roboto_Light_40, minimum, 1}, {625, 420, &Roboto_Light_40, "Maximum", 0}, {790, 466, &Roboto_Light_40, maximum, 1}, {18, 570, &Roboto_Light_36, dates, 0}, {122, 570, &Roboto_Light_36, dates + 8, 0}, {227, 570, &Roboto_Light_36, dates + 16, 0}, {342, 570, &Roboto_Light_36, dates + 24, 0}, {466, 570, &Roboto_Light_36, dates + 32, 0}, {450, 240, &Roboto_Light_36, prices, 0}, {450, 322, &Roboto_Light_36, prices + 16, 0}, {450, 401, &Roboto_Light_36, prices + 32, 0}, {450, 483, &Roboto_Light_36, prices + 48, 0}, }; // Function to draw our graph void drawGraph() { // Edge Coordinates int x1 = 10; int y1 = 535; int x2 = 500; int y2 = 205; int textMargin = 68; // Set min to a very high value, and max to very low, so that any real world data changes it float minData = 1e9F; float maxData = -1e9F; // Find min and max in data for (int i = 0; i < 31; ++i) { minData = min(minData, data[i]); maxData = max(maxData, data[i]); } // Copy current, min and max data to har arrays to be displayed dtostrf(data[30], 8, 2, current); strcat(current, "$"); dtostrf(minData, 8, 2, minimum); strcat(minimum, "$"); dtostrf(maxData, 8, 2, maximum); strcat(maximum, "$"); // Temporary buffer char temp[64]; for (int i = 0; i < 4; ++i) { dtostrf(minData + (float)i / 4 * (maxData - minData), 5, 0, temp); strncpy(prices + 16 * (3 - i), temp, 16); } // Find current day in a month int day; sscanf(date + 3, "%d", &day); // Find days to display underneath the graph for (int i = 0; i < 5; ++i) { itoa(((day - i * 7) % 31 + 31) % 31, temp, 10); strncpy(dates + 8 * (4 - i), temp, 8); } // Used for drawing lines int prev_x = -1; int prev_y = -1; // Draw gradients for (int i = 0; i < 31; ++i) { // Calculate heights and current x value for a data point int tx = x1 + i * (x2 - x1 - textMargin) / 31; float v = data[i]; int h = (int)((float)(v - minData) * (float)abs(y1 - y2) / (float)abs(maxData - minData)); int ty = y1 - h; // If i is not 0, hence prev x and y exsist so draw gradients under them if (i) { // Rise over run for one pixel float dy = (float)(ty - prev_y) / (float)((x2 - x1 - textMargin) / 31); // Draw a gradient line from every pixel to bottom line in graph line for (int j = 0; j < (x2 - x1 - textMargin) / 31 + 1; ++j) display.drawGradientLine(prev_x + j, (int)round((float)prev_y + dy * (float)j), prev_x + j, y1, 3, 7); } // Set previous x and y prev_x = tx; prev_y = ty; } // After drawing gradients, draw lines for (int i = 0; i < 31; ++i) { // Calculate heights and current x value for a data point int tx = x1 + i * (x2 - x1 - textMargin) / 31; float v = data[i]; int h = (int)((float)(v - minData) * (float)abs(y1 - y2) / (float)abs(maxData - minData)); int ty = y1 - h; // If i is not 0, hence prev x and y exsist so draw lines if (i) { display.drawThickLine(prev_x, prev_y, tx, ty, 0, 5.0); } // Set previous x and y prev_x = tx; prev_y = ty; } // Draw grid for (int i = 0; i < 4; ++i) display.drawFastHLine(x1, y2 + i * (y1 - y2) / 4, x2 - x1, 4); for (int i = 0; i < 5; ++i) display.drawFastVLine(x1 + i * (x2 - x1) / 5, y2, y1 - y2, 4); display.drawFastVLine(x2 - textMargin + 2, y2, y1 - y2, 4); display.drawThickLine(x1, y1, x2, y1, 0, 3); } // Our main drawing function void drawAll() { // Do a full refresh every fullRefresh times, defined above if (refreshes % fullRefresh == 0) { // Initial screen clear display.clearDisplay(); // Save current date string, more about it in Network.cpp network.getTime(date); // Find current day from string int day; sscanf(date + 3, "%d", &day); // Find what month is it numericly and display it for (int i = 0; i < 12; ++i) { if (strncmp(months[i], date, 3) == 0) sprintf(fromToDate, "%d.%d to %d.%d", ((i + 1) % 12 ? i + 1 : 12), day, ((i + 2) % 12 ? i + 2 : 12), day); } // Draw graph drawGraph(); // Draw our UI elements for (int i = 0; i < sizeof(elements) / sizeof(elements[0]); ++i) { // Text settings display.setTextColor(0, 7); display.setFont(elements[i].font); display.setTextSize(1); // 0 is aligned by left bottom corner, 1 by right if (elements[i].align == 0) display.setCursor((int)(elements[i].x * 0.96), (int)(elements[i].y)); else if (elements[i].align == 1) { int16_t x, y; uint16_t w, h; // Get hot much the textx offsets pointer and draw it that much more left display.getTextBounds( elements[i].text, 0, 0, &x, &y, &w, &h); display.setCursor((int)(elements[i].x * 0.96) - w, (int)(elements[i].y)); } // Print out text to above set cursor location display.print(elements[i].text); } // Display all display.display(); } else { // Just draw time int i = 1; // Initial screen clear display.clearDisplay(); // Save current date string, more about it in Network.cpp network.getTime(date); // Text settings display.setTextColor(0, 7); display.setFont(elements[i].font); display.setTextSize(1); // 0 is aligned by left bottom corner, 1 by right if (elements[i].align == 0) display.setCursor((int)(elements[i].x * 0.96), (int)(elements[i].y)); // Print out text to above set cursor location display.print(date); // Just update time display.partialUpdate(); } } void setup() { // Begin serial communitcation, sed for debugging Serial.begin(115200); // Initial display settings display.begin(); display.clearDisplay(); display.clean(); display.setTextWrap(false); // Welcome screen display.setCursor(50, 290); display.setTextSize(3); display.print(F("Welcome to Inkplate 6 btc/eth tracker example!")); display.display(); delay(5000); // Our begin function network.begin(); } void loop() { // Do a new network request every fullRefresh times, defined above if (refreshes % fullRefresh == 0) while (!network.getData(data)) { Serial.println("Retrying retriving data!"); delay(1000); } // Our main drawing function drawAll(); // Go to sleep before checking again esp_sleep_enable_timer_wakeup(1000L * DELAY_MS); (void)esp_light_sleep_start(); // Increment refresh count ++refreshes; }