Crypto Ticker
This example have 10 crypto currencies to the display. Cycle through them by pressing the triangle button.
Data from Coin Cap API
Note
If you haven’t download the code:
Download examples from github termod-s3
Unzip the downloaded termod-s3-main.zip
Or just clone the repository
git clone https://github.com/TAMCTec/termod-s3.git
Open termod-s3/examples/crypto_ticker/crypto_ticker.ino
with Arduino IDE.
As it require internet connection, you need to change the ssid and password to connect to your wifi network under secret.h
.
Remember to select ESP32S3 Dev Module
and port, then click upload.
#include <TFT_eSPI.h>
#include <TAMC_FT62X6.h>
#include <WiFi.h>
#include <Wire.h>
#include <ArduinoJson.h>
#include <HTTPClient.h>
#include <stdlib.h>
#include "crypto_ticker.h"
#include "secret.h"
#define DISPLAY_PORTRAIT 2
#define DISPLAY_LANDSCAPE 3
#define DISPLAY_PORTRAIT_FLIP 0
#define DISPLAY_LANDSCAPE_FLIP 1
#define DISPLAY_WIDTH 240
#define DISPLAY_HEIGHT 320
// Instances
TFT_eSPI tft = TFT_eSPI();
TAMC_FT62X6 tp = TAMC_FT62X6();
// Global variables
HTTPClient http;
DynamicJsonDocument coinData(1024);
String header;
bool wifiFailed = false;
const char* coinId;
const char* coinSymbol;
const char* coinPrice;
const char* coinRank;
const char* coinChange24Hr;
String symbol = String(coinSymbol);
double price = 0;
String rank = String(coinRank);
double change24HrValue = round(String(coinChange24Hr).toFloat());
int currentCoinId = 0;
int lastCoinId = -1;
bool displayNeedReflash = false;
bool dataNeedReflash = false;
// Functions
void setStatus(int status);
void touchHandler();
bool coinGetData(String id);
void displayDrawMain(void);
void displayReflashData(void);
void displayDrawMessage(String msg);
void displayDrawMessage(String msg1, String msg2);
bool wifiInit();
String significentNumber(double f, int num);
void setup(void) {
Serial.begin(115200);
Serial.println("Crypto Ticker Start!");
Wire.begin();
tft.init();
tp.begin();
tp.setRotation(DISPLAY_LANDSCAPE);
tft.setRotation(DISPLAY_LANDSCAPE);
tft.fillScreen(TFT_BLACK);
}
int lastX = -1;
int lastY = -1;
int retryCount = 0;
unsigned long previousMillis = 0;
unsigned long currentMillis = 0;
void loop() {
if (WiFi.status() == WL_CONNECTED){
currentMillis = millis();
touchHandler();
if (currentMillis - previousMillis > REFLASH_DELAY || dataNeedReflash) {
bool success = false;
setStatus(STATUS_BUSY);
for (retryCount=0; retryCount<RETRY_COUNT; retryCount++){
if (coinGetData(COINS[currentCoinId])){
success = true;
break;
}
}
if (!success) {
setStatus(STATUS_ERROR);
displayDrawMessage("Get Data Error");
} else {
setStatus(STATUS_DONE);
if (displayNeedReflash) {
displayDrawMain();
displayNeedReflash = false;
}
displayReflashData();
}
setStatus(STATUS_IDLE);
dataNeedReflash = false;
}
if (currentMillis - previousMillis > LOOP_DELAY) {
previousMillis = currentMillis;
}
}
else {
if (wifiInit()){
Serial.println(WiFi.localIP().toString());
String msg = String("IP: ") + WiFi.localIP().toString();
displayDrawMessage("Connected", msg);
delay(2000);
displayDrawMain();
}
}
}
// Status
void setStatus(int status) {
tft.fillCircle(300, 20, 10, status_colors[status]);
}
/*
* Touch Handler
*/
void touchHandler() {
int x = 0;
int y = 0;
tp.read();
if (tp.isTouched) {
x = tp.points[0].x;
y = tp.points[0].y;
if (lastX == -1) {
if (y > 70 && y < 140) {
if (x > 0 && x < 50) {
currentCoinId--;
if (currentCoinId < 0) {
currentCoinId = COINS_LENGTH - 1;
}
dataNeedReflash = true;
displayNeedReflash = true;
} else if (x > 270 && x < 320) {
currentCoinId++;
if (currentCoinId >= COINS_LENGTH) {
currentCoinId = 0;
}
dataNeedReflash = true;
displayNeedReflash = true;
}
}
lastX = x;
lastY = y;
}
} else {
lastX = -1;
lastY = -1;
}
}
/*
* Display
*/
void displayDrawMain(void) {
tft.fillScreen(TFT_BLACK);
tft.setFreeFont(FF18);
tft.setTextDatum(TR_DATUM);
tft.setTextColor(TFT_WHITE);
tft.drawString("Rank:", 170, 150, GFXFF);
tft.drawString("Change 24hr:", 170, 180, 4);
tft.fillTriangle(320 - 30, 90, 320 - 30, 120, 320 - 10, 105, TFT_PINK);
tft.fillTriangle( 30, 90, 30, 120, 10, 105, TFT_PINK);
for (int i=0; i<COINS_LENGTH; i++){
if (i == currentCoinId){
tft.fillCircle(60+(i*20), 220, 6, TFT_PINK);
} else {
tft.fillCircle(60+(i*20), 220, 2, TFT_WHITE);
}
}
}
void displayReflashData(void) {
String id = String(coinId);
String _symbol = String(coinSymbol);
double _price = String(coinPrice).toFloat();
String _rank = String(coinRank);
double _change24HrValue = String(coinChange24Hr).toFloat();
if (currentCoinId != lastCoinId) {
symbol = _symbol;
tft.fillRect(0, 0, 200, 50, TFT_BLACK);
// Symbol
tft.setFreeFont(FF19);
tft.setTextDatum(TL_DATUM);
tft.setTextColor(TFT_WHITE);
tft.drawString(symbol, 10, 10, GFXFF);
lastCoinId = currentCoinId;
}
// Price
if (price != _price){
if (_change24HrValue < 0){
tft.setTextColor(TFT_RED);
} else {
tft.setTextColor(TFT_GREEN);
}
price = _price;
String priceString = String("$") + significentNumber(price, 5);
tft.fillRect(50, 80, 220, 50, TFT_BLACK);
tft.setFreeFont(FF20);
tft.setTextDatum(MC_DATUM);
tft.drawString(priceString, 160, 100, GFXFF);
}
// Rank
if (rank != _rank){
rank = _rank;
tft.fillRect(200, 150, 320, 20, TFT_BLACK);
tft.setFreeFont(FF18);
tft.setTextDatum(TL_DATUM);
tft.setTextColor(TFT_WHITE);
tft.drawString(rank, 200, 150, GFXFF);
}
// Change 24 hour
if (change24HrValue != _change24HrValue){
change24HrValue = _change24HrValue;
String change24Hr = significentNumber(change24HrValue, 4) + String("%");
tft.fillRect(200, 180, 320, 20, TFT_BLACK);
tft.setFreeFont(FF18);
tft.setTextDatum(TL_DATUM);
tft.setTextColor(TFT_WHITE);
tft.drawString(change24Hr, 200, 180, 4);
}
}
void displayDrawMessage(String msg) {
tft.fillRoundRect(40, 50, 240, 140, 10, TFT_BLACK);
tft.drawRoundRect(40, 50, 240, 140, 10, TFT_CYAN);
tft.setFreeFont(FF17);
tft.setTextDatum(MC_DATUM);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.drawString(msg, 160, 120, GFXFF);
displayNeedReflash = true;
}
void displayDrawMessage(String msg1, String msg2) {
tft.fillRoundRect(40, 50, 240, 140, 10, TFT_BLACK);
tft.drawRoundRect(40, 50, 240, 140, 10, TFT_CYAN);
tft.setFreeFont(FF17);
tft.setTextDatum(MC_DATUM);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.drawString(msg1, 160, 110, GFXFF);
tft.drawString(msg2, 160, 130, GFXFF);
displayNeedReflash = true;
}
bool coinGetData(String id) {
Serial.print("[HTTP] begin...\n");
http.begin("https://api.coincap.io/v2/assets/" + id); //HTTP
Serial.print("[HTTP] GET...\n");
int httpCode = http.GET();
if(httpCode > 0) {
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
if(httpCode == HTTP_CODE_OK) {
String payload = http.getString();
deserializeJson(coinData, payload);
Serial.println(payload);
coinId = coinData["data"]["id"];
coinSymbol = coinData["data"]["symbol"];
coinPrice = coinData["data"]["priceUsd"];
coinRank = coinData["data"]["rank"];
coinChange24Hr = coinData["data"]["changePercent24Hr"];
http.end();
return true;
}
} else {
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
http.end();
return false;
}
}
/*
* Wi-Fi
*/
bool wifiInit() {
displayDrawMessage("Connecting to", WIFI_SSID);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
return wifiConnecting(WIFI_SSID);
}
bool wifiConnecting(String msg){
int WLcount = 0;
while (1) {
++WLcount;
delay(500);
if (WLcount > WIFI_TIMEOUT * 2) {
displayDrawMessage("Connection Failed");
delay(2000);
return false;
}
if (WiFi.status() == WL_CONNECTED){
return true;
}
}
}
String significentNumber(double f, int num){
String result = String(f, num);
result = result.substring(0, num+1);
if (result.indexOf(".") < 0 || result.indexOf(".") == 5){
result = result.substring(0, num);
}
return result;
}
#define WIFI_TIMEOUT 10 // Second
#define FF20 &FreeSans24pt7b
#define FF19 &FreeSans18pt7b
#define FF18 &FreeSans12pt7b
#define FF17 &FreeSans9pt7b
#define GFXFF 1
#define LOOP_DELAY 10000 // 100 ms
#define REFLASH_DELAY 10000 // 10 Second
#define RETRY_COUNT 10
#define STATUS_BUSY 0
#define STATUS_IDLE 1
#define STATUS_ERROR 2
#define STATUS_DONE 3
uint16_t status_colors[] = {TFT_YELLOW, TFT_WHITE, TFT_RED, TFT_GREEN};
String DOLLOR = "$";
/*
* Coins
*/
#define COINS_LENGTH 10
String COINS[COINS_LENGTH] = {
"bitcoin",
"ethereum",
"binance-coin",
"cardano",
"tether",
"polkadot",
"xrp",
"uniswap",
"litecoin",
"chainlink",
};
#define WIFI_SSID "1002"
#define WIFI_PASSWORD "27148043"