Brian Moreau

Search my site

    Maker Portfolio   
ESP8266 WiFi Enabled Twitter Search Enabled LED Belt Buckle
April 2018

Particle Electron GPS

LED Belt Buckle
Voltage Regulator Module

So a friend of mine gave me an LED Belt Buckle.
It was always an intention of mine to WiFi enable it so that maybe people could send a message to it and it would display that message.
I decided to instead have it display Tweets where it can display tweets of a particular search term, which still allows people to send it a custom message, albeit through Twitter.
Since its WiFi and gets its power from batteries it makes a nice stand alone Twitter message display system, or even a small unit that can be used for events, performances and exhibitions providing audience interaction.

The circuit is built using an ESP8266-01 WiFi module. These are very inexpensive and can be programmed using the Arduino IDE.
The ESP-01 is the smallest and cheapest of the ESP range and only has minimal input and output options. Luckily we only require two outputs to control the buttons on the Belt Buckle so it will service for this project. The Digital Outputs simply go LOW to simulate a press of the two program buttons which are ENTER and PID on my Buckle. Using these buttons manually to program in messages takes a lot of time since each letter of the alphabet has to be scrolled through one by one however when programming using the ESP, messages can be entered much faster and more importantly automatically.

The ESP chips contain a Web Server and Access Point so it can both make Web requests and act as an Access Point to allow configuration via WiFi.

The Access Point Name and Password are pre programmed into the device. When you connect you need to browse to its IP Address and you will then be shown a Configuration Page where you enter in the Twitter Search Term. This can be your Twitter account @name which will result in Tweets directed at you to be displayed or it can be a trending topic or hashtag.

Since the unit is designed to be portable it made sense to include a configuration page where you enter the WiFi Internet Settings. You can then change these easily when you move it to other locations.

There are many versions of these buckles and while most work in a similar way they often have different character sets and programming patterns, thus my code may not be transferable to other buckles.

Unfortunately my Belt Buckle did not have an @ symbol and since its only four characters wide it makes reading messages a little awkward. It is however a cheap and fun project to make since it made use of items I already had.
It forms the backbone of an enhanced device that could utilise a larger LED Display.

It also gave me valuable experience using these very cheap, small and versatile ESP WiFi units.

ESP8255 WI-Fi LED Belt Buckle


The circuit consists of the WiFi module, the Belt Buckle and a variable voltage regulator module.

WI-Fi LED Belt Buckle Circuit

Since the Belt Buckle was originally powered by two 3V Coin Cells it required a 6V Supply which is fed direct from the batteries. A variable voltage regulator module was used to step down the 6V to 3.3V for the ESP.
The ESP draws about 800mA so C Cells were used to ensure the unit could run for many hours on a full charge.

My Belt Buckle program buttons simply shorted the program input pins to 0V so by directly connecting a single wire to one side of each of the two buttons and taking this line LOW simulates a button press as all circuits use a common GND.

Program Port
Foreseeing the requirement to modify the ESP program I decided to make it possible to connect a programming lead. This was achieved by splitting in half a Telephone lead joining connector. This produces two sockets, one is used to connect to the ESP Program pins and the other half has three wires that connect it to my USB ESP-01 Programmer. I can then simply program it by connecting a standard telephone lead between programmer and unit.

The programs consist of two parts, the Arduino Code which is uploaded to the ESP8266 and the Server Code that is placed on a web server.

You will obviously need some webspace where you can upload the PHP script.
This script or webpage is accessed by the ESP with a simple web request.
The script then connects to the Twitter API to retrieve the Tweets. You will thus also require a Twitter App API Key.

This method is required since the Twitter API requires authentication by oAuth and the ESP-01 is unable to make web connections of this type directly. The PHP code thus conducts these calls when requested to do so and then passes the Tweet back to the ESP.

I won’t go into how to program the ESP units as this information can already be found from a number of sources on the web. All I will say is they can be a little awkward and temperamental since they do not have an onboard USB program port.

I should add that the server script dose not check for any kind of authentication from the ESP device and thus if the URL was known to others then they could use it to get Tweets themselves from any device they choose. This could result in you hitting Twitter API request limits.

Arduino Code

// FOR ESP8266-01

// Show when not connected
// checking Wi-Fi Config page shows connected to last connected AP
// Display too small

// API URL  This will be where you place this code
// yourdirectoryname/_espGetTweets.php?q=searchterm
// default search term = London

// TCP Client
WiFiClient client;

// ESP Webserver
ESP8266WebServer webServer(80);


// ESP AP Server
// password can be blank 
// must be min 8 chars or will not work
const char *APName = "ESPTWIT1";
const char *APPass = "ED8F5GA2"; 

// Timer

// enter a default message
String defaultMsg = "TWEET ME AT BRIANMOREAU  ";
String searchTerm = "London";

// domain name of server where this twitter API script is
char server[] = "";
uint8_t httpPort = 80;

// wi-fi config
// ESP Auto stores last connection
// so can be blank if its previously connected
// as wont call connect unless not connected
// will need a not connected LED MAYBE
// wifi config vars
char ssid[32];
char pass[32];
String SSIDX;
String PASSX;

int ENTER = 2; // GPIO2 
int PID = 0; // GPIO0
// GPIO1 1 Oboard Blue LED + TX
int faultLED = 1;
int faultState = 0;

// in code programs are num 0 - 5
uint8_t programNum = 0;
String text;
uint8_t x;
bool connectFlag = false;
uint8_t giveup = 1;

Timer getTweetsTimer;
uint8_t getTweetsTimerID;

Timer cycleDisplayTimer;
uint8_t cycleDisplayTimerID;

uint8_t numberOfTweets = 0;
uint8_t currentDisplayID = 0;

void setup() {


  // get stored wifi data
  SSIDX = WiFi.SSID();
  PASSX = WiFi.psk();
  // store in char array
  // pin config
  pinMode(ENTER, OUTPUT);
  pinMode(PID, OUTPUT);
  pinMode(faultLED, OUTPUT);
  digitalWrite(ENTER, HIGH);
  digitalWrite(PID, HIGH);
  // turn fault led off
  digitalWrite(faultLED, HIGH);
  // start the access point server
  WiFi.softAP(APName, APPass);
  // define web link functions
  webServer.on("/", doRoot);
  webServer.on("/setup", doSetup);
  webServer.on("/save", doSave);
  // start server
  // program in default msg
  text = defaultMsg;
  //programNum = 1;
  numberOfTweets = 0;
  currentDisplayID = 1;
  cycleDisplayTimerID = cycleDisplayTimer.every(60000, cycleDisplay);
  getTweetsTimerID = getTweetsTimer.every(600000, conTCP);

void loop() {

  // check if connected to wifi
  // exp8266 will automatically connect using last settings as they are automatically stored
  // flash fault LED for visual when wifi is bust
  // if wi-fi turns off WL_CONNECTED state doesent appear to change
  if (giveup <= 4) { // try 5 times
    if (WiFi.status() != WL_CONNECTED) {
      while (WiFi.status() != WL_CONNECTED) {
        //Serial.println("Connecting to wifi ");
        WiFi.begin(ssid, pass);
        if (giveup > 5) break;
      } // end while not connected
    } else {
      // reset the giveup count as connected
      giveup = 1;
    } // end if not connected to wifi
  } // end giveup

  // keep checking to see if someone connects to device

  // update timers

  // get data from buffer if connected
    if (connectFlag == true) {
      if (client.available() > 0) {
        if (client.find("BEGINTWEET")) {
          String thisTweetTxt = client.readStringUntil('\n');
          text = thisTweetTxt;
          connectFlag = false;
         } // end if find
       } // end if available
      } // end if connect = true

  // flash fault LED if cant connect
  if (giveup > 5) {
    if (faultState == 0) {
      digitalWrite(faultLED, LOW); // ON
      faultState = 1;
    } else {
      digitalWrite(faultLED, HIGH); // OFF
      faultState = 0;


} // end loop

void cycleDisplay() {
  if (numberOfTweets == 0) {
    // do nothing
    // keep displaying intro message
  } else if (numberOfTweets >= currentDisplayID) {
    // advance display message by 1
    digitalWrite(PID, LOW);
    digitalWrite(PID, HIGH);
    if (currentDisplayID <= 5) {
    } else {
      // back to main intro message
    currentDisplayID = 1;
  } else if (currentDisplayID > numberOfTweets) {
    // advance back to start intro message when all spacews not programmed
    int advance = 6 - numberOfTweets;
    for (int x = 0; x < advance; x++) {
      digitalWrite(PID, LOW);
      digitalWrite(PID, HIGH);
      if (currentDisplayID <= 5) {
      } else {
      // back to main intro message
      currentDisplayID = 1;
} // end cycle display

// will keep trying forever
void conTCP() {
  if (client.connect(server, httpPort)) {
      // connected to resource
      // send data
      client.print("GET /apps/esp/_espGetTweets.php?q=");
      client.println(" HTTP/1.1");
      //client.println("Content-Length: " + String(searchTerm.length()));
      client.println("User-Agent: ESP8266");
      client.println("Connection: close");
      connectFlag = true;
    } else {
      // No connection to server
      // should maybe keep retrying else waits till next call
    } // end if connect
} // end get tweets

void programTweet() {
    // select program mode
    // disable message change function timer
    // enter display program mode

    // advance program number 1 to 5
    if (programNum <= 4) {
    } else {
      programNum = 1;
    // update current display id
    currentDisplayID = programNum;
    // and number of tweets
    if (numberOfTweets <= 4) {
    } else {
      numberOfTweets = 5;
    // loop through tweet text and program in each letter
    // need to know display max message length
    // - 2 to get rid of ending 
in HTML for (int letters = 0; letters < text.length()-2; letters++) { // keep checking for server connection // while programming letters, works OK webServer.handleClient(); char c = text.charAt(letters); // if space if (c == 32) { selectLetter(26); } // if letter A - Z , A 65 - Z 90 else if (c > 64 && c < 91) { int l = c - 65; selectLetter(l); } // if number 0 -9 0 48 - 9 57 else if (c > 47 && c < 58) { selectLetter(c); } } // end for // fin selecting letters program(); // force the message to be displayed for at least 30 seconds delay(30000); } // end program tweet // select program mode , also acts to deselect program mode or fin entering text void program() { digitalWrite(ENTER, LOW); digitalWrite(PID, LOW); delay(1000); digitalWrite(PID, HIGH); delay(1000); digitalWrite(ENTER, HIGH); delay(1000); } // program numbers 0 to 5 void selectProgramNum() { for (x = 0; x <= programNum - 1; x++) { digitalWrite(PID, LOW); delay(500); digitalWrite(PID, HIGH); delay(500); } // select it select(); } // select letter void selectLetter(int lt) { for (x = 0; x < lt; x++) { delay(100); digitalWrite(PID, LOW); delay(100); // 100 ok digitalWrite(PID, HIGH); } // select it delay(200); select(); } void select() { digitalWrite(ENTER, LOW); delay(200); // 200 OK digitalWrite(ENTER, HIGH); delay(200); // 200 OK } // triggers when ROOT is browsed void doRoot() { // get variables from connection and make it the twitter search term String var = webServer.arg (0); if (var != "") { searchTerm = var; } // write HTML String html; // make it mobile friendly html = "<meta name='viewport' content='width=device-width, initial-scale=1'>"; html += "<h2>Twitter LED Display</h2>"; html += "<p>Search Term: " + searchTerm + "<BR>"; html += "<FORM ACTION='/'>"; // ROOT html += "<INPUT TYPE='TEXT' NAME='searchText'>"; html += "<INPUT TYPE='SUBMIT'></p>"; html += "</FORM>"; html += "<BR><BR>"; html += "<a href='/setup'>WiFi Setup</a>"; webServer.send(200, "text/html", html); } void doSetup() {   // get number of access points detected   int n = WiFi.scanNetworks();   String html;   html = "<meta name='viewport' content='width=device-width, initial-scale=1'>";   html += "<h2>Wi-Fi Config</h2>";   html += "<p>Connected to: " + String(ssid) + "</p>";   html += "<p>STATUS: " + String(WiFi.status()) + "</p>";   html += "<p>Select Access Point to connect to:</p>";   // Print SSID for each network found   html += "<FORM ACTION='/save'>"; //   html += "<SELECT NAME='SSID'>";   for (int i = 0; i < n; ++i) {     html += "<option value='" + WiFi.SSID(i) + "'>" + WiFi.SSID(i) + "</option>";   } // end for   html += "</SELECT><BR><BR>";   html += "Password:<br>";   html += "<INPUT TYPE='TEXT' NAME='PASS'>";   html += "<INPUT TYPE='SUBMIT'>";   html += "</FORM>";   html += "<BR><BR>";   html += "<a href='/'>Back to index</a>";   // need page refresh   webServer.send(200, "text/html", html); } // end doSetup

void doSave() {   // saves new wi-fi config   // get variables from connection   SSIDX = webServer.arg (0);   PASSX = webServer.arg (1);   // set valuse as ssid and pass   SSIDX.toCharArray(ssid,SSIDX.length()+1);   PASSX.toCharArray(pass,PASSX.length()+1);
  // output status   String html;   html = "<meta name='viewport' content='width=device-width, initial-scale=1'>";   html += "<h2>Wi-Fi Service Updated</h2>";   html += "<p>SSID = " + String(ssid) + "<br></p>";   // not nessary to reset but may be best   html += "<p>Please cycle power</p>";   html += "<BR><BR>";   html += "<a href='/'>Back to index</a>";   webServer.send(200, "text/html", html);
  // stop current connection   // kicks user off access point also   WiFi.disconnect();   // reset giveup counter   giveup = 1;   // turn fault led off   digitalWrite(faultLED, HIGH);
  // try make new connection 5 times   if (giveup <= 4) {     if (WiFi.status() != WL_CONNECTED) {       while (WiFi.status() != WL_CONNECTED) {         WiFi.begin(ssid, pass);         delay(5000);         giveup++;         if (giveup > 5) break;       } // end while not connected     } else {       // reset the giveup count as connected       giveup = 1;     } // end if not connected to wifi   } // end if giveup } // end do save


Website Server Code

# _espGetTweets.php
# for ESP8266 LED Message Display of Tweets
# Arduino Code LED_Belt_Buckle_Controler_IOT_TwitterV5

# set YOUR twitter app keys
$conskey = "YOURAPPKEYS";
$conssec = "YOURAPPKEYS";

# search API URL
$search_url = '';
$userToken = "YOURUSERTOKEN";
$userSecret = "YOURUSERKEY";
# connect to api
$oauth = new OAuth($conskey,$conssec,OAUTH_SIG_METHOD_HMACSHA1,OAUTH_AUTH_TYPE_URI);
$q = urlencode($_GET[q]); // serach query
$c = urlencode($_GET[num]); // number of results
$c = "1";
# build search query
$lang = urlencode("en");
$args = array('q'=>$q,
$json = json_decode($oauth->getLastResponse(),true);

# decode result
foreach($json['statuses'] as $tweet) {
//$id = $tweet['id'];
$text = $tweet['text'];
// remove URL's
// get pos of start of url
// case-insensitive search
$posLINK = stripos($text, "HTTPS://");
// find how many characters remaining
if ($posLINK) {
$r = strlen($text) - $posLINK;
// if not end of text
if ($r + $posLINK != strlen($text)) {
} else {
// extract link
$text = substr($text, 0, $posLINK);
echo("BEGINTWEET" . $text . "<br>");

ESP8266 WI-Fi Web Config



Readers comments >

Sorry there are no comments, be the first to leave a comment.

Leave a comment or ask me a question >

You don’t need to register to leave a comment because I feel people should not be forced to register to have their say.
All comments are checked prior to publishing to prevent spam.
Don’t worry this wont take long.
If you supply your email address below you will automatically be notified when I approve your comment.

Full name > *
eMail address > (not published)
Website > (http://...)
Location > (town or city)
Comment or question > *
Human *
  * feilds required  
WiFi Enabled Twitter Enabled LED Belt Buckle
© 2008 - 2021 - Brian Moreau

Valid XHTML 1.0 Transitional Valid CSS!