inkplate-6-arduino-library/examples/3. Projects/03-Crypto_tracker_example/03-Crypto_tracker_example.ino

384 lines
11 KiB
C++

/*
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.
Here we use Coingecko API to get latest cryptocurrency prices and display
them on the Inkplate screen. If you wish to change the currecny, you can
edit it below.
IMPORTANT:
Make sure to change your timezone and wifi credentials below
Also have ArduinoJSON installed in your Arduino libraries, download here: https://arduinojson.org/
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, 2 means UTC+2
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";
// You can find your currency id here:
// https://api.coingecko.com/api/v3/coins
// If it loads weirdly you can search the JSON using ctrl/command+f for
// your crypto by name and then find it's id next to it's name and copy those above
//----------------------------------
// Include Inkplate library to the sketch
#include "Inkplate.h"
// Include fonts used
#include "Fonts/Roboto_Light_160.h"
#include "Fonts/Roboto_Light_36.h"
#include "Fonts/Roboto_Light_40.h"
// Our networking functions, declared in Network.cpp
#include "Network.h"
// create object with all networking functions
Network network;
// create display object
Inkplate display(INKPLATE_3BIT);
// Delay between API calls in miliseconds
#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
double 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},
};
// Our functions declared below setup and loop
void drawGraph();
void drawAll();
void setup()
{
// Begin serial communitcation, sed for debugging
Serial.begin(115200);
// Initial display settings
display.begin();
display.clean();
display.clearDisplay();
display.setTextWrap(false);
display.setTextColor(0, 7);
// Welcome screen
display.setCursor(70, 230);
display.setTextSize(2);
display.println(F("Welcome to Inkplate 6 cryptocurrency tracker example!"));
display.setCursor(70, 250);
display.println(F("Connecting to WiFi..."));
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;
}
// 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
double minData = 1e9F;
double 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]);
}
double span = max(0.3D, (double)abs(maxData - minData));
// Copy current, min and max data to char 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 + (double)i / 4 * span, 5, (maxData < 10.0D ? 3 : 0), temp);
strncpy(prices + 16 * (3 - i), temp, 16);
}
// Find current day in a month
int day;
sscanf(date + 3, "%d", &day);
// Find current month
int month = 0;
for (int i = 0; i < 12; ++i)
{
if (strncmp(months[i], date, 3) == 0)
month = ((i + 2) % 12 ? i + 2 : 12);
}
// Find days to display underneath the graph
for (int i = 0; i < 5; ++i)
{
itoa(((day - i * 7) % 31 + 31) % 31, temp, 10);
itoa(month - ((day - i * 7) <= 0), temp + 32, 10);
strncpy(dates + 8 * (4 - i), temp, 8);
strcat(dates + 8 * (4 - i), ".");
strcat(dates + 8 * (4 - i), temp + 32);
strcat(dates + 8 * (4 - i), ".");
}
// 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;
double v = data[i];
int h = (int)((double)(v - minData) * (double)abs(y1 - y2) / span);
int ty = y1 - h;
// If i is not 0, hence prev x and y exist so draw gradients under them
if (i)
{
// Rise over run for one pixel
double dy = (double)(ty - prev_y) / (double)((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((double)prev_y + dy * (double)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;
double v = data[i];
int h = (int)((double)(v - minData) * (double)abs(y1 - y2) / span);
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.", day, ((i + 1) % 12 ? i + 1 : 12), day,
((i + 2) % 12 ? i + 2 : 12));
}
// 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();
}
}