Why?

With the latest craze in the world of cryptocurrency and, as coin hodlers ourselves, we wanted to have a tiny desktop display cycling through the current prices of different coins. 

Cryptocurrency coins

Although we can certainly find the same information using apps and websites (for free!), we discovered that having a dedicated device on our desks displaying the data constantly minimized the time we spent on tracking it.  Not to mention that building the device is a great excuse to work on a ESP8266-powered, internet-connected, DIY electronics project for any Maker out there! (bro/sis, do you even IoT?)

What?

The main goal is to have a dedicated, inexpensive, device that would help us avoid repeatedly checking websites, apps, email, writing scripts, etc., in order to monitor the ups and downs of coin prices.

In terms of what's required, we challenged ourselves to use the minimum number of parts, and require no special tools/skills such as soldering.

Where?

As we're not the only hodlers out there with a knack for electronic DIY gadgets, we're documenting the parts list and build instructions on this project page for anyone to use.  To make it even easier for those wanting to give the project a try, we'll have a kit available on our site (ACROBOTIC Industries) when we're done with the design.

As with all our projects, the software is free and Open Source!

How?

The hardware

To build a price tracker for cryptocurrency we simply needed two pieces of hardware: an internet-capable microcontroller to gather the data, and a screen to display it, we tried to find the best solution considering ease of use and cost.

OLED display

Given our main goal of having a device with a small form factor that could sit on our desks, the first choice was to use a 0.96" OLED screen to display the price data.

ACROBOTIC 0.96in OLED Graphic Display I2C (SSD1306, 128x64 pixels, Blue/Yellow)

Not only are these displays small (and bright!), but they're very easy to control over i2c merely having to connect 4 wires to our microcontroller or single-board computer: 2 for power and ground, and 2 for the data and clock lines.

ESP8266 microcontroller (SoC)

What can we say about the ESP8266 that hasn't been said about the wheel, sliced bread, or the iPhone... we love it! It's the most convenient, inexpensive way to have a microcontroller running code while connected to a Wi-Fi network.

ESP8266 onboard the WeMos D1 Mini

The SoC comes in a variety of modules, breakouts, and development boards. For this project, we evaluated a few options and settled WeMos D1 Mini for its compactness and availability of an OLED Shield that we could connect without the need of doing any wiring.

The software

Running on the microcontroller, we need software that's able to query the price data from dedicated servers, as well as to control the OLED screen to display the queried data.

Price data API

As of this writing, the best sites that provide a free API to query the current prices of different cryptocurrencies are:

Even better, at the moment they neither of them requires an API key, so we only need to write the firmware to perform queries and parse the result to obtain the necessary data.

Firmware

To perform the two tasks mentioned above, namely, query/parse data and control the OLED screen, we use a piece of code running on the ESP8266.

The firmware performs 4 major tasks:

1. Connecting to the Internet

Using the built-in Arduino library for the ESP8266 and entering our WiFi network credentials (ssid/password) we connect to the internet.

2. Querying the data

Using the built-in Arduino library for the ESP8266 , we create a WebClient object that allows us to send a GET request to the servers' APIs and retrieve the price data.

3. Parsing the data

Using Benoît Blanchon's fantastic Arduino JSON library (available in  the Library Manager), we can easily get the parts of the JSON-formatted data that interest us.

4. Displaying the data

Using a couple of OLED Arduino libraries, it's straight forward to display the price data on the screen as well as our custom graphics. Most of the work, however, goes into making the UI both intuitive and aesthetically pleasing.

Once the project is completed, the final resting place of the firmware shall be:

Thanks for stopping by!


First prototype

We started building the proof-of-concept prototype for the ESPicker using our preferred parts for the job. The main reason is that we had code snippets from previous projects and tutorials that we could re-use. Namely, the venerable DevKit ESP8266 development board and a standard SSD1306-powered, 0.96", 128×64 OLED screen.

ACROBOTIC ESP8266 ESP-12E Development Board IOT Arduino NodeMCU

Wiring

Wiring the two is straight-forward, keeping in mind that we need 2 4.7KΩ resistors to pull up the I2C lines. The I2C pins on the DevKit board are GPIO4 for SDA (labeled D2) and GPIO5 for SCL (labeled D1), this we wire them to the corresponding pins on the OLED screen PCB as shown in the diagram below:

Using the default I2C pins for the ESP8266 allows us to simply use the built-in Wire library for I2C communication. With everything wired up, it's time to test some code.   

Fetching cryptocurrency data

The very first thing we do is forget about the OLED screen and simply figure out how to get the data that we'll eventually display on it. We use the Serial Monitor for printing out the data, and worry about the OLED later.

To get the data we first try to find where is it freely available. A Google Search reveals 2 popular services we can use, CoinMarketCap and Coindesk. Looking through their APIs let us know that we can access the current price for different cryptocurrencies by sending a GET request to:

If we simply point our browser to either of the URLs we'll see the data that we're after. However, to do so with the ESP8266, we need to first connect to the internet, and then use a web client.

Although both services work great, we'll stick with Coindesk for this project.

1. Connecting to the internet

Using the built-in ESP8266WiFi.h library, we use the begin method of the WiFi object with a couple of character arrays as arguments, which contain the credential to the network.

const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED)
{   
  delay(500);   Serial.print("."); 
}

As is typical, we do this inside the setup() function. Also, we use a while() loop to monitor the state of the connection. The loop runs until the connection is successful, though this blindly assumes that the network is available–a way to make the code more robust would be to handle cases where the connection isn't successful.

2. Using a web client

Using the built-in ESP8266WiFi.h library, we create an instance of the WiFiClient class, set up the request we're going to send to the Coindesk server, and declare the buffer where we'll store the server's response.

We also construct the request we're going to send to the server, specifying a minimum set of header fields that are needed.

#define CD_API "/v1/bpi/currentprice.json"
#define CD_URL "api.coindesk.com"

WiFiClient client;
static char respBuffer[4096];

const char request[] = 
  "GET " CD_API " HTTP/1.1\r\n"
  "User-Agent: ESP8266/0.1\r\n"
  "Accept: */*\r\n"
  "Host: " CD_URL "\r\n"
  "Connection: close\r\n"
  "\r\n";    

Next, we attempt to connect to the host site using the connect() method of the WiFiClient object. We do some basic error handling if the connection isn't successful, but once again we assume it will be successful.

Using the print() method of the WiFiClient object (not to be confused with its counterpart from the Serial class), we send the request. We then close and flush the connection, and we also wait an arbitrary-but-reasonable amount of time (1 second) for the server to respond.

Once the server responds, we use a while() loop to load the response into our character buffer. To do this, we use the read() method of the WiFiClient object.

if (!client.connect(CD_URL, 80))
{
  Serial.println("Connection failed");
  return;
}

client.print(request);
client.flush();
delay(1000);

uint16_t index = 0;
while(client.connected())
{
  if(client.available())
  {
    respBuffer[index++] = client.read();
    delay(1);
  }
}

By the design of the API to which we send the request, we know that the response from the server will be formatted in JSON.

Parsing JSON-formatted data

Although we know that the data is formatted in JSON, is we print out the character buffer we notice that there's some extra characters in the server's response. For this reason we use the strchr() method to trim the buffer (creating a new one) all the way to the first opening curly brace '{' where we know, by inspection, that the JSON-formatted data begins.

char * json = strchr(respBuffer,'{');

DynamicJsonBuffer jBuffer;
JsonObject& root = jBuffer.parseObject(json);
Serial.println("JsonObject: ");
root.prettyPrintTo(Serial);
Serial.println();

JsonObject& bpi = root["bpi"];
JsonObject& usd = bpi["USD"];
String tmp = usd["rate_float"];
data = tmp;

Serial.print("BTC (USD): $");
Serial.println(data); 

Using the fantastic ArduinoJson library we can now parse the data. We can do so by creating either a Static or Dynamic JsonBuffer object (we chose the later), and calling its respective parseData() method.  The JsonBuffer object(s) then allow us to pick the data we want by using the familiar keyed array notation.

For now, we can visualize the data in the Serial Monitor using the print() method of the Serial object (remember to initialize it in the setup() function!). But, the next step is to send it over to the OLED screen.

Displaying the data

Although several libraries exist (including our own!) for working with OLED screens, we chose to follow our quick-n-dirty standalone OLED demo:

As such, we created a helper file util.h containing a few constants including the font data. Please note that the file should be located in the same folder as the .ino sketch.

Then, it was a matter of creating a few low-level helper functions for setting up the OLED screen, and communicating with it. And one high-level function to print the data we wanted:

setTextXY(0,0);     // Set cursor 0th page (row), 0th column
displayString("BTC/USD:");

void printData(String data)
{
  setTextXY(2,0);
  displayString("$");
  setTextXY(2,1);
  char __data[sizeof(data)];
  data.toCharArray(__data, sizeof(__data));
  displayString(__data);
}

We also encapsulated the data capture and parsing inside a getData() function, and the data displaying on the OLED screen inside the prinData() function.  These two functions are called from within the standard loop() function every 10 seconds.

Proof of concept prototype for the ESP8266 cryptocurrency tracker
Proof-of-concept prototype

The prototype's firmware files are available at:


The ESPicker

With a solid functional prototype in hand we now move on to making it nicer, and turning it into something that anyone can use, wether they want to program it themselves or not. To do this we focus on the following improvements:

Increased portability

As mentioned earlier, our goal is to have a small-sized, set-and-forget, physical device to display cryptocurrency prices continuously. To such end, and despite the joys of breadboarding, we choose to use the compact WeMos D1 Mini together with a compatible OLED Shield.

Although the form factor and plug-and-play nature of the WeMos is great, we need to adapt the firmware to use the reduced screen resolution of the WeMos OLED Shield (64×48). Luckily, the SparkFun Micro OLED library works with the shield (uses the same SSD1306 driver), and it is meant for the screen's resolution.

So now, instead of including the "util.h" file, we can simply:

#include <SFE_MicroOLED.h> // Include the SFE_MicroOLED library

#define PIN_RESET 255
#define DC_JUMPER 0 // I2C Addres: 0 - 0x3C, 1 - 0x3D

MicroOLED oled(PIN_RESET, DC_JUMPER); // I2C

 This creates the class instance oled, which we can use in the setup() function to configure the hardware: 

// Before you can start using the OLED, call begin() to init
// all of the pins and configure the OLED.
oled.begin();
// clear(ALL) will clear out the OLED's graphic memory.
// clear(PAGE) will clear the Arduino's display buffer.
oled.clear(ALL);  // Clear the display's memory (gets rid of artifacts)
// To actually draw anything on the display, you must call the
// display() function. 
oled.display();   

  Lastly, we can modify our printData() function to use the available methods:

void printData(String price, int font)
{  
  oled.clear(PAGE);
  oled.setFontType(font);
  oled.setCursor(0,0);
  oled.print("BTC/USD:");
  oled.setCursor(0,10);
  oled.print("$");  
  oled.setCursor(6,10);
  oled.print(price);
  oled.display();
  delay(1500);
  oled.clear(PAGE);
}

If we upload the modified firmware, we see the basic data from our prototype, but now in the smaller screen:

ESP8266 WeMos D1 Mini V2 Development Board

Additional software features

Now that we have a functional device, we can focus on improving the UI. Stay tuned for details!

Configurable through a Web Interface [in progress]

[coming soon!]

Price-based alerts [in progress]

[coming soon!]

Track additional cryptocurrencies and display prices in other currencies [in progress]

[coming soon!]

Show historical change in pricing (%) [in progress]

[coming soon!]

Additional hardware features

To improve the usability and durability of the ESPicker, a couple of must-haves are battery-powered operation, and a protective case.

3d-printed enclosure [done]

Given our goal of having the ESPicker sit on our desks, we wanted a way to tilt the angle of the display. Thus, we decided to add a cradle to the enclosure so that we could rotate it up and down. The design also includes a clip mechanism for the back cover, which makes it easy to secure and remove it.

Battery-powered operation [in progress]

[coming soon]

The End