995. Physical Computing

From API to LED: Digital Details

Lets call it CRYPT0MANIA – the connected crystal.

This post is about the crystals digital details – because it works – it really works!

Note: For a summary of the sculpture overall, read more here. For details on how the physical enclosure was made, read more here

Electronics & Wiring

The device inside the crystal is the same WeMos wifi micro-controller described here, just with a few updates. Inside are just two tiny LEDs (one red, and one green) and the wiring necessary for the WeMos to control it.

one single LED for each side

It is able to live and breathe from a 12V DC connection from the wall. This is the single cord you see exiting the crystal.

Here is a fritizing diagram of the circuit with pin D5 as the green LED pin and D6 as the red. It also includes a switch to control power to the LEDs without turning off the unit completely.

The crystal was able to live and breathe during the ITP Winter Show thanks to a local sandbox network on the floor.

Key Steps and functions of the code (full code below):

#  Function Description
1 connectToWifi()  Connect to Wi-fi based on the ssid and password for a nearby network
2 getAPIValues() Connect to

This was done with a combination of code from this awesome guy and some esp8266wifi documentation from GitHub

3 getAPIValues() Parse the webpage information – find the ‘1-hour’ keyword with indexOf function, then transform it into a nice decimal value (float value).
4 glowCrystal() Translate that decimal value (API_val in the example below) into a digital signal for the LED.

This is done by using the constrain function to limit the results – currently set between +4% and -4%. Then using the map function to get a pwm value (between 0 and 1024) to analogWrite to an LED.

5 glowCrystal() Create a pulsating effect using sin() and a cycle counter (with millis) to modify the digital signal value and give it the glowing effect we see.

Here is the full raw code:

//Crypt0Mania code by Calebfergie

/* thanks to ESP docs: fingerprint from github, wemos vid guy:, arduino examples: millis & MAC address*/

#include <ESP8266WiFi.h> //include wifi library

const int greenLedPin = D5; // the pin that the red LED is attached to
const int redLedPin = D6; // the pin that the green LED is attached to

//API and PWM variables
float API_val; //percentage value from website
float API_val_1000; //scaled up for int mapping to pwm
float percent_contraint = 4.0;
float API_val_constrain; //constrained between 0 and 4 or -4%
float pwmVal;
float modVal;
float multiplier;

//Timer Variables
float counter = 1;
long prior_millis = 0;
long interval = 20000;
unsigned long millis_t;

//Web variables

//Redacted wifi info
const char* ssid = "yourNeworkName";
const char* password = "UrNtwrkP55word";

const char* host = ""; // remote server we will connect to
const char* fingerprint = "EF 9D 44 BA 1A 91 4C 42 06 B1 6A 25 71 26 58 61 BA DA FA B9"; // fingerprint of certificate as per website

WiFiClientSecure client;

//text parsing variables
String result, condensedResult;
String startingVal = "percent_change_1h";
int startingPoint, endingPoint;

void setup() {
 Serial.begin(115200); // initialize serial communications
 pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output so it can be turned off
 pinMode(greenLedPin, OUTPUT);
 pinMode(redLedPin, OUTPUT);
 delay(2000); //just wait a 2 secs

void loop() {
 unsigned long millis_t = millis(); //millis at the current time
 digitalWrite(LED_BUILTIN, HIGH); // on the WeMos this turns OFF the bright blue light on the board
 glowCrystal(); //illuminate and animate the crystal based on current api values
 if (millis_t - prior_millis > interval) { //every interval, do the following
 counter = 1; //reset the counter for the glow effect
 multiplier = (sin(counter) + 1) / 2.0; // redefine the multiplier value
 //GET THE VALUES from the web - end value should be a pwmVal, a number between 0 and 1024
 prior_millis = millis_t;
 counter = counter + 0.02; //bump up the counter for the multiplier

//function to see stats in the console
void consoleStats() {
 Serial.print("current time (seconds): ");
 Serial.print(millis_t / 1000);
 Serial.print(" | ");
 Serial.print("pwmVal: ");
 Serial.print(" | ");
 Serial.print("multiplier: ");
 Serial.print(" | ");
 Serial.print("modVal: ");
 Serial.print(" | ");
 Serial.print("counter: ");

void connectToWifi () {
 Serial.print("Connecting to ");
 Serial.println(ssid); //print status to console
 WiFi.begin(ssid, password); //log in to the network
 while (WiFi.status() != WL_CONNECTED) { //print waiting
 Serial.println("\nWiFi connected"); //print success
 Serial.print("IP address: ");
 Serial.println(WiFi.localIP()); //print IP
 Serial.print("MAC address: ");
 Serial.println(WiFi.macAddress()); //print MAC address

void getAPIValues() //client function to send/receive GET request data. Mixed with another example from github
//Try to connect to the host
Serial.print("connecting to ");
if (!client.connect(host, 443)) {
Serial.println("connection failed");
//use a fingerprint to verify - not sure if this is necessary
if (client.verify(fingerprint, host)) {
Serial.println("certificate matches");
} else {
Serial.println("certificate doesn't match");
client.println("GET /v1/ticker/ethereum/ HTTP/1.1"); //GET request
client.println("Connection: close"); //close 1.1 persistent connection
client.println(); //end of get request
Serial.println("request sent"); // note to self

while (client.connected() && !client.available()) delay(1); //waits for data
while (client.connected() || client.available()) { //connected or data available
char c =; //gets byte from ethernet buffer
result = result + c;
deleteHttpHeader(); //thanks to wemos guy

startingPoint = result.indexOf(startingVal); //idenfity where our target data starts
condensedResult = result.substring(startingPoint + 21, startingPoint + 26); // get the characters needed (it is known to be 5)
API_val = condensedResult.toFloat(); // turn it into an float
Serial.print("Condensed Result (1 hour percentage change): ");
Serial.print("| API_val: ");
client.stop(); //stop client

//function used to delete header info from recieved data
void deleteHttpHeader()
 if (result.endsWith("Content-Type: text/plain"))
 result = "";


void glowCrystal() {
 multiplier = (sin(counter) + 1) / 2.0; // a sine wave value that goes between 0 and 1
 API_val_1000 = API_val*1000; // beef up the value for more precise mapping
 if (API_val_1000 > 0) { //if positive
 API_val_constrain = constrain(API_val_1000, 0, percent_contraint*1000); //constrain the value to the top percentage
 pwmVal = map(API_val_constrain, 0, percent_contraint*1000, 0, 1024);//map the value to a pwm with max of 1024 (wemos)
 modVal = pwmVal * multiplier; //modify the value to pulse via a sine wave
 analogWrite(redLedPin, 0); // keep the red LED off
 analogWrite(greenLedPin, modVal); //light up the green LED based on the value
 } else { // if negative
 API_val_constrain = constrain(API_val_1000, -1* percent_contraint*1000, 0);
 pwmVal = map(API_val_constrain, 0, -1*percent_contraint*1000, 0, 1024);
 modVal = pwmVal * multiplier;
 analogWrite(greenLedPin, 0); // keep the green LED off
 analogWrite(redLedPin, modVal); //light up the red LED based on the value


2 replies on “From API to LED: Digital Details”

Leave a Reply

Your email address will not be published. Required fields are marked *