Mark Fischer

12 minute read

I recently picked up one of Adafruit’s new HUZZAH32 Feather development boards, without having a clear project in mind for it. However after browsing the Adafruit forums, I stumbled across someone who was making a sort of status screen for their office, and I thought I would try that out.

The basic idea is to have a little box with an LCD screen on it which would display my current status. Like, if I’m in a meeting, at lunch, or home sick.


For this guide I assume the following knowledge and prior setup:

Basic requirements:

  • Network capabilities of some sort. WiFi seems the best for this.
  • HTTP Stack available to make API calls.
  • Some sort of screen.

I had an old character LCD from years ago, so I decided to try and use that as a screen, and the HUZZAH32 has on board WiFi and HTTP example code, so I was off to the breadboard!

Design and Layout

First I set out connecting up the 16x2 Character LCD screen. Since the Feather has plenty of IO pins, I can just use use 6 pins to connect directly to the LCD screen without requiring the I2C backpack (which is super useful if you don’t have tons of pins).

// Connect direct with GPIO pins
// LCD          Feather
// --------     --------
// 4  - RS      25
// 6  - EN      26
// 14 - DB7     32
// 13 - DB6     15
// 12 - DB5     33
// 11 - DB4     27

The LCD screen also needs a potentiometer connected to control the screen brightness, as well as a bunch of other pins connected to 5V and Ground. See Adafruit’s learning guide on LCDs for a great overview of these little screens.

I also included a pushbutton to toggle the LCD backlight, so that its not always on.

These types of Character LCD screens need +5V power for VCC and to light the backlight. The logic pins seem to be 3.3V tolerant though fortunately. So we need to pull power off the USB pin which will be 5V when you’re powering the HUZZAH32 via USB. If I want to power this from a battery, I’ll have to figure out some way to boost the 3.7V from a LiPoly up to 5V to power the screen.

After connecting everything up on a breadboard for testing, it was time to make it more permanent.

Perma-Proto Board Assembly

Adafruit sells these great little perma-proto boards. They’re laid out just like a breadboard, with power rails and a center gutter etc. So you can pretty much just pick up your design from the breadboard, stick it on the perma-proto and solder it up!

Since I’m not using all of the pins on the Feather, I only need to solder on a few headers to the perma-proto for stability. I’m also going to mount the LCD screen on the under side of the proto board.

Next I wired up the rest of the connections, potentiometer, and pushbutton.

I did make one mistake while soldering things up. I originally put the pushbutton straddling the center gutter. This had the unintended side affect of bridging the +5V power from above and connecting it down to one of the LCD data pins. This took me several frustrating hours with a multimeter to track down. :) Fortunately it was an easy fix to cut the leg off the pushbutton.

3D Printed Case

This was also my first time designing a 3d printed case for a project. I spent a couple hours watching the Adafruit 3D modeling tutorials, especially the one on designing parametric snap-fit cases. A couple of hours later, I had my first case design!

I’m really fortunate to work at The University of Arizona, and we have a great little maker space as part of the library system, and they do 3D printing. So I was able to upload my STL files to them and a couple of days later went over to pick up my prints.

Arduino Code


First off was trying to get the Feather onto my WiFi. This was a pretty new development board from Adafruit in 2018 so there wasn’t a whole lot of great how-tos on it yet. Fortunately espressif, the makers of the ESP32 chip on the Feather have a pretty decent Arduino core with example sketches up on github. Particularly the BasicHttpClient example.

I tend to hide the SSIDs of my networks at home, but this seems to cause problems with the Feather. So I created a guest network, 2.4GHz, with the SSID visible. I could get WPA2 security working fortunately.

 1#include <WiFi.h>
 2#include <WiFiMulti.h>
 4void setup()
 6    WiFiMulti.addAP("arduino", "<password>");
 8    while( != WL_CONNECTED) {
 9        Serial.print(".");
10    }
12    Serial.println("");
13    Serial.println("WiFi connected");
14    Serial.print("IP address: ");
15    Serial.println(WiFi.localIP());
16    Serial.println(WiFi.macAddress());

Getting on WiFi turned out to be pretty easy for the most part, so thanks so much to the espressif folks for these libraries!

The WiFi.macAddress() method seems to return a random MAC address until you actually connect to a network. So if you need the MAC address, be sure to connect to a network you know you can get onto first.

I need to pull down my current status from somewhere on the web. My first attempt was just a static text file on a web server I have access to. But updating it there was a bit of a pain, and not very “Internet of Things-y”. So I decided to play around with, the IoT service Adafruit offers.

Since this project just needs to read data from a feed, we don’t need to mess around with API keys or any form of authentication. Create a new feed in your console, and make it public.

In the feed, you can manually enter data to set the status.

Once that is set up you can test your feed in any web browser by simply visiting the following URL:

Substitute your username and feed key for estranged and mark-status respectively. Limiting the feed to 1 item, and only getting the value field limits the size of the JSON response, making it easier to parse. You can play around with removing those parameters from the URL and see how the results change.

With the feed in place, and WiFi connected, we’re ready to retrieve our feed. Adafruit maintains an IO library, but for this project I wanted to try my hand at parsing JSON directly so that I know how to do it for arbitrary API calls. It turns out there is a fantastic ArduinoJson library out there which works really well, and you can just add via the library manager in the Arduino IDE. I’m also using the HTTPClient library that comes with the Espressif esp-32 Arduino setup.

Note! This example only works with un-encrypted HTTP URLs. Not with HTTPS connections. The HTTPClient library does support SSL/TLS certificates but the setup is more involved. See the BasicHttpClient example for hints on how to work with certificates, but I have not got this working yet.

 1#include <HTTPClient.h>
 2#include <ArduinoJson.h>
 4StaticJsonBuffer<200> jsonBuffer;
 6void loop()
 8    // Create an HTTPClient object
 9    HTTPClient http;
11    // Setup our URL
12    http.begin("");
14    // start connection and send HTTP header
15    int httpCode = http.GET();
17    // httpCode will be negative on error
18    if(httpCode > 0) {
19        // HTTP header has been sent and Server response header has been handled
20        Serial.printf("[HTTP] GET... code: %d\n", httpCode);
22        // Successful connection: Status code of 200
23        if(httpCode == HTTP_CODE_OK) {
24            // Retrieve and print out the raw response
25            String payload = http.getString();
26            Serial.println(payload);
28            // jsonBuffer must be cleared each time through the loop, otherwise it fills up.
29            jsonBuffer.clear();
30            // be careful to never reference jsonArray outside this loop, as it will be undefined
31            // when the buffer is cleared.
32            JsonArray& jsonArray = jsonBuffer.parseArray(payload);
34            // Retrieve the value field from the json data and print it.
35            const char* statusValue = jsonArray[0]["value"];
36            Serial.println(statusValue);
37        }
38    } else {
39        Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
40    }
42    http.end();
44    delay(60000);

LCD Screen

I had an old 16 column, 2 row Character LCD screen I got around 10 years ago when I first started playing with Arduinos. Fortunately they haven’t really changed and are still well supported on new development boards. Adafruit of course has a great guide on getting started with these sort of screens. Since I have plenty of IO pins on the Feather, I’m just using 6 data pins to connect to the LCD screen.

 1#include "Adafruit_LiquidCrystal.h"
 3#define PIN_RS 25
 4#define PIN_EN 26
 5#define PIN_DB7 32
 6#define PIN_DB6 15
 7#define PIN_DB5 33
 8#define PIN_DB4 27
10Adafruit_LiquidCrystal lcd(PIN_RS, PIN_EN, PIN_DB4, PIN_DB5, PIN_DB6, PIN_DB7);
12void setup()
14    lcd.begin(16, 2);
15    lcd.print("Starting up");

One additional fun thing I learned about on the Adafruit LCD guide was that you can program up to 8 custom characters on the LCD, and the display them wherever you’d like. I thought it would be fun to animate a little WiFi icon while it was starting up, so I created 3 separate custom characters, and then cycle through them during the startup phase.

I found just sort of mapping out the characters as a byte array works pretty well. Each 1 is a pixel of the character that will be on, and the zeros are all off.

 1// Custom Character Designer
 3byte wifi3[8] = {
 4  B00000,
 5  B01110,
 6  B10001,
 7  B00000,
 8  B00100,
 9  B01010,
10  B00000,
11  B00100,
14void setup()
16  lcd.begin(16, 2);
18  // Write the custom character to the LCD. There are 8 custom slots, 0-7. We're writing to slot 2.
19  lcd.createChar(2, wifi3);
21  // Set the cursor position on the LCD screen, then display your custom character
22  // 0 is row 1
23  // 15 is the last character on the row
24  lcd.setCursor(15, 0);
25  lcd.write(byte(2));


This was a really fun project, and one of the first that sort of feels ‘finished’ to me, as it has a little case and everything. I will probably do another revision of the case, as I forgot to include a hole for the USB cable to thread through. Also the board stack inside is a little loose, since its only connected together with header pins. I’m going to try and include some more mounting posts on the side for the Feather to screw into.

I hope you found it interesting and helpful. If you have any questions hit me up on Twitter.

Like this article or have questions?

Full Code

  2 *  This sketch sends a message to a TCP server
  3 *
  4 */
  6#include <WiFi.h>
  7#include <WiFiMulti.h>
  8#include <HTTPClient.h>
  9#include "Adafruit_LiquidCrystal.h"
 10#include <ArduinoJson.h>
 12WiFiMulti WiFiMulti;
 14// Connect direct with GPIO pins
 16// LCD          Feather
 17// --------     --------
 18// 4  - RS      25
 19// 6  - EN      26
 20// 14 - DB7     32
 21// 13 - DB6     15
 22// 12 - DB5     33
 23// 11 - DB4     27
 26#define PIN_RS 25
 27#define PIN_EN 26
 28#define PIN_DB7 32
 29#define PIN_DB6 15
 30#define PIN_DB5 33
 31#define PIN_DB4 27
 33Adafruit_LiquidCrystal lcd(PIN_RS, PIN_EN, PIN_DB4, PIN_DB5, PIN_DB6, PIN_DB7);
 35// Custom Character Designer
 37byte wifi1[8] = {
 38  B00000,
 39  B00000,
 40  B00000,
 41  B00000,
 42  B00000,
 43  B00000,
 44  B00000,
 45  B00100,
 48byte wifi2[8] = {
 49  B00000,
 50  B00000,
 51  B00000,
 52  B00000,
 53  B00100,
 54  B01010,
 55  B00000,
 56  B00100,
 59byte wifi3[8] = {
 60  B00000,
 61  B01110,
 62  B10001,
 63  B00000,
 64  B00100,
 65  B01010,
 66  B00000,
 67  B00100,
 70StaticJsonBuffer<200> jsonBuffer;
 72void setup()
 75  Serial.begin(115200);
 76  delay(10);
 78  lcd.begin(16, 2);
 79  delay(20);
 81  lcd.createChar(0, wifi1);
 82  lcd.createChar(1, wifi2);
 83  lcd.createChar(2, wifi3);
 85  // Print a message to the LCD.
 86  lcd.setCursor(0, 0);
 87  lcd.print("Starting up");
 89  // We start by connecting to a WiFi network
 90  WiFiMulti.addAP("networkname", "password");
 92  Serial.println();
 93  Serial.print("Wait for WiFi... ");
 95  lcd.setCursor(15, 0);
 96  lcd.write(byte(0));
 97  delay(200);
 98  lcd.setCursor(15, 0);
 99  lcd.write(byte(1));
100  delay(200);
101  lcd.setCursor(15, 0);
102  lcd.write(byte(2));
103  delay(200);
104  lcd.setCursor(15, 0);
105  lcd.write(byte(1));
106  delay(200);
107  lcd.setCursor(15, 0);
108  lcd.write(byte(0));
110  while( != WL_CONNECTED) {
111      Serial.print(".");
112      lcd.setCursor(15, 0);
113      lcd.write(byte(0));
114      delay(200);
115      lcd.setCursor(15, 0);
116      lcd.write(byte(1));
117      delay(200);
118      lcd.setCursor(15, 0);
119      lcd.write(byte(2));
120      delay(200);
121      lcd.setCursor(15, 0);
122      lcd.write(byte(1));
123      delay(200);
124  }
126  Serial.println("");
127  Serial.println("WiFi connected");
128  Serial.print("IP address: ");
129  Serial.println(WiFi.localIP());
130  Serial.println(WiFi.macAddress());
132  delay(500);
136void loop()
139    // Use WiFiClient class to create TCP connections
140    HTTPClient http;
142    http.begin(""); //HTTP
144    // start connection and send HTTP header
145    int httpCode = http.GET();
147    // httpCode will be negative on error
148    if(httpCode > 0) {
149        // HTTP header has been send and Server response header has been handled
150        Serial.printf("[HTTP] GET... code: %d\n", httpCode);
152        // file found at server
153        if(httpCode == HTTP_CODE_OK) {
154            String payload = http.getString();
155            Serial.println(payload);
157            jsonBuffer.clear();
158            JsonArray& jsonArray = jsonBuffer.parseArray(payload);
159            Serial.println(jsonBuffer.size());
160            const char* statusValue = jsonArray[0]["value"];
161            Serial.println(statusValue);
162            String statusString = String(statusValue);
164            int newLineIndex = statusString.indexOf("|");
165            Serial.println(newLineIndex);
166            String lineOne = statusString;
167            String lineTwo;
168            if (newLineIndex > 0) {
169              lineOne = statusString.substring(0, newLineIndex);
170              lineTwo = statusString.substring(newLineIndex + 1);
171            }
172            lcd.clear();
173            lcd.setCursor(0, 0);
174            lcd.print(lineOne);
175            if (newLineIndex > 0) {
176              lcd.setCursor(0, 1);
177              lcd.print(lineTwo);
178            }
179        }
180    } else {
181        Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
182    }
184    http.end();
186    delay(60000);