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

398 lines
11 KiB
Arduino
Raw Normal View History

/*
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/
2020-07-30 13:52:43 +02:00
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
2020-08-06 14:43:47 +02:00
edit it below.
IMPORTANT:
Make sure to change your timezone and wifi credentials below
2020-07-30 13:52:43 +02:00
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
2020-07-30 13:52:43 +02:00
//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_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 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
2020-07-30 13:52:43 +02:00
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
2020-08-06 14:43:47 +02:00
char *months[] ={
"Jan"
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
};
//Out UI elements data
2020-08-06 14:43:47 +02:00
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
2020-07-30 13:52:43 +02:00
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]);
}
2020-07-30 13:52:43 +02:00
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)
{
2020-07-30 13:52:43 +02:00
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
2020-07-30 13:52:43 +02:00
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);
2020-07-30 13:52:43 +02:00
itoa(month - ((day - i * 7) <= 0), temp + 32, 10);
strncpy(dates + 8 * (4 - i), temp, 8);
2020-07-30 13:52:43 +02:00
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;
2020-07-30 13:52:43 +02:00
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
2020-07-30 13:52:43 +02:00
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,
2020-08-06 14:43:47 +02:00
(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;
2020-07-30 13:52:43 +02:00
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)
2020-07-30 13:52:43 +02:00
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();
}
}