Screen Shot 2019-07-26 at 3.53.17 PM.png

A DO-IT-YOURSELF ARDUINO PROJECT

With a little basic Arduino knowledge (Easily teach yourself online for free! Start here.) anyone can make this awesome project. Really! It was my 2nd project ever! I got the inspiration, instructions, and code for this project from a fantastic person who created it and posted it on Hackster.io for all of us to enjoy. Go to that link if you want more detailed instructions than I have posted here, or if you need links to purchase supplies. I knew it would be amazing as soon as I read his description:

Build this simple project with about $25 worth of electronics!
NO soldering, NO advanced skills, and NO Barb!
— Rajarshi Nigam
Screen Shot 2019-07-26 at 5.05.18 PM.png

GET THE PARTS

ESP8266 MODULE (The brains)
This little Arduino-based board has it’s own WiFi network built right in.

WS2811 LED LIGHTS
Not just any LEDs will do! These are “individually addressable” lights, meaning you can tell each one when to turn on and off. Very important for this project!

FEMALE-TO-FEMALE JUMPER WIRES
The easiest way to hook up your control board to your lights.

THE REST OF THE DISPLAY
How you mount your lights is totally up to you, so get creative! Some people have made this into a wearable costume. Or you can mount them onto a board covered in 80’s style floral wallpaper and scrawl the letters on with black paint just like the frantic Joyce Byers. I embellished my modern looking WS8211 lights by putting them inside old large bulb C9 Christmas lights for that just-dragged-from-the-attic look! The point is, the finishing touches are up to you - so have a great time making your display!

Screen Shot 2019-07-26 at 5.26.49 PM.png

PUT IT TOGETHER

This part is really simple!

WS2811 lights have 3 wires: positive, ground, and data. Data is usually the center wire, but check to be sure for your particular lights.

Instead of plugging your lights into the wall, you will “plug them in” to your ESP8266 board. You may need to separate and strip about 1/4” of covering off the wires at that end.

Then, insert the exposed wire into the end of a female-to-female jumper. Secure with electrical tape or heat shrink and repeat for the other two wires.

Now, attach the free end of your jumper to the pins on your ESP8266.

The positive wire goes to the pin marked “VIN” or “5V.”

The ground wire goes to the pin marked “GND.”

Finally, the data wire will go to the pin marked “D4.” You can attach the data wire to a different pin, but you MUST then change the code to tell the board which pin you are using for the data.

Screen Shot 2019-07-26 at 5.51.26 PM.png

WRITE (or copy) THE CODE

You don’t need to be able to write your own code for this project because I’m sharing mine with you. Scroll down and copy the code below, then paste it into your Arduino software.

I think one of the best ways to learn code is to play with some that is already written. Try making adjustments to it and see what works.

This is exactly how I came up with this code. I got my inspiration from someone who created it from scratch. Then I made some adjustments to suit my needs, et voila!

This version of the project works all on its own. No WiFi needed other than that generated by your ESP8266. The board requires USB power, and can be run off a regular outlet, or go fully wireless and use a battery pack for cell phones.

If you want to get really advanced, follow this link to the original project on Hackster.io - you can set up a “backend” and alter the code so that people can text their message to the lights! (Requires existing WiFi network.)

COPY ALL THE TEXT BELOW THIS LINE.
PASTE INTO YOUR ARDUINO SOFTWARE


#define FASTLED_ALLOW_INTERRUPTS 0
#include "FastLED.h"
#include <ESP8266WiFi.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>



// WIFI settings
#define WIFI_SSID "STRANGER WIFI"

// Network settings
#define DNS_PORT 53
#define WEB_PORT 80

IPAddress apIP(192, 168, 1, 1);
DNSServer dnsServer;
ESP8266WebServer webServer(WEB_PORT );

#define PAGE \
"<!DOCTYPE html>"\
"<html>"\
"<head>"\
  "<title>Stranger Lights</title>"\
  "<meta name='viewport' content='initial-scale=1, maximum-scale=1'>"\
"</head>"\
"<body style='text-align: center;'>"\
  "<h3>STRANGER LIGHTS</h3>"\
  "<form>"\
    "<p>Enter your message below!</p>"\
    "<input type='text' name='message'><br>"\
    "<input type='submit' value='Send via the Upside Down'>"\
  "</form>"\
"</body>"\
"</html>"



// the milliseconds to give each letter
#define MILLIS_PER_LETTER 1300

// number of LEDs in the strip
#define NUM_LEDS 50

// the data pin the green wire from the LEDs are connected to
#define DATA_PIN 4

// an array to keep track of the LEDs
CRGB leds[NUM_LEDS];

// the message we will display
String message;

// the time we received the message
unsigned long received;

// the default millis per letter
//int millis_per_letter;

// we'll use all 26 letters of the alphabet
#define NUM_LETTERS 26

// the LED number (start counting from 0) that we light up to show our message
const int LETTER_LEDS[NUM_LETTERS] = {
 /*A*/  25
,/*B*/  24
,/*C*/  23
,/*D*/  22
,/*E*/  21
,/*F*/  20
,/*G*/  19
,/*H*/  18
,/*I*/  9
,/*J*/  10
,/*K*/  11
,/*L*/  12
,/*M*/  13
,/*N*/  14
,/*O*/  15
,/*P*/  16
,/*Q*/  17
,/*R*/  8
,/*S*/  7
,/*T*/  6
,/*U*/  5
,/*V*/  4
,/*W*/  3
,/*X*/  2
,/*Y*/  1
,/*Z*/  0
};

// how many colors to cycle through for the lights
#define NUM_COLORS 4

void setup() {
  // send print statements at 9600 baud
  Serial.begin(9600);

  // initialize the LEDS
  FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);

  // set them all to be off
  fill_solid(leds, NUM_LEDS, CRGB::Black);
  FastLED.show();

  // create the wifi network
  Serial.print("Creating the Network");
  Serial.println(WIFI_AP);
  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
  WiFi.softAP(WIFI_SSID);

  // if DNSServer is started with "*" for domain name, it will reply with
  // provided IP to all DNS request
  dnsServer.start(DNS_PORT, "*", apIP);

  // replay to all requests with same HTML
  webServer.onNotFound([]() {
    Serial.println(webServer.uri());
    Serial.print("message: ");
    String data = webServer.arg("message");
    if(data.length()){
      webServer.send(200, "text/html", PAGE);
      data.toLowerCase();
      Serial.println(data);
    
      // remember the message and the time it came in
      message = data;
      received = millis();
    }
    webServer.send(200, "text/html", PAGE);
  });
  webServer.begin();

  // this message will show until it is overwritten
  message = "the quick brown fox jumps over the lazy dog";
  received = millis();
}


void loop() {
  dnsServer.processNextRequest();
  webServer.handleClient();

  // how many milliseconds have elapsed since the last message came in
  unsigned long elapsed = millis() - received;

  // assuming MILLIS_PER_LETTER, what letter (index) ofthe message should we be on?
  int index = (elapsed/MILLIS_PER_LETTER)%message.length();

  // get the character letter we should print
  char letter = message.charAt(index);

  // if the character is between 'a' and 'z' (no numbers, spaces, or punctuations)
  if(letter >= 'a' && letter <= 'z'){
    // how bright to make this LED from 0 to 1, this is what makes them fade in and out
    // it calculates what percent we are completed with the letter, and makes it fade in from 0-50% and fade out from 50-100%
    // the formula can be visualized here: https://www.desmos.com/calculator/5qk8imeny4
    float brightness = 1-abs((2*(elapsed%MILLIS_PER_LETTER)/((float)MILLIS_PER_LETTER))-1);
    uint8_t value = 255 * brightness;
    
    // get the LED number the letter should be in, assuming our array starts at 'a' and ends at 'z'
    int letter_index = letter-'a';
    int led = LETTER_LEDS[letter_index];

    // get a rotation of colors, so that every NUM_COLORS lights, it loops
    // e.g. red, yellow, green, blue, red, yellow green blue
    uint8_t hue = (letter_index%NUM_COLORS*255)/NUM_COLORS;

    // set that LED to the color
    leds[led] = CHSV(hue, 255, value);
    FastLED.show();
    // set it to black so we don't have to remember the last LED we turned on
    leds[led] = CRGB::Black;
    
    Serial.print(letter);
    Serial.print("\t!");
    Serial.print(led);
    Serial.print("\t=");
    Serial.print(brightness);
    Serial.print("\t@");
    Serial.print(elapsed);
    Serial.println();
  } else {
    // if the letter wasn't a-z then, we just turn off all the leds
    FastLED.show();
  }
}