LED WiFi Hat

A self-contained, fully cusomisable LED display board on a hat, WiFi enabled for Web based setup.

Similar projects worth following
Several well known tech items goes into this hat. It combines a single ESP8266 (ESP-07) WiFi module with WS2812 LED strips (black, weather protected, 60/m), with a cheapo novelty gentlemans hat and a 3D printed brim-rounded strip mount point along the front.
Of course all the gubbins are housed inside the body of the hat, which makes it a little bit top heavy, but does sit on the head reasonably well. The majority of the extra weight comes from the battery.

I'm using the Arduino ESP8266 environment, combined with cnlohr's i2s driven LED driver library which was adapted for the Arduino library by 'JoDa'.

The display is only 18 pixels wide by 7 pixels tall, giving it a modest total of 126 LEDs. This works out okay as too many would be a bit of a power drain - I'm using a three cell LiPo ~1000mAh battery from HobbyKing to provide juice, and because I'm not producing full display brightness (Text scroller for now) it has ran for about two hours straight without running out of battery life - still counting.

I custom wrote a text scroller routine which uses a simple 1 bit / pixel font definition in a simple 2d byte array. The WiFi libraries fully utilised to provide an access point and web page with which you can change the scrolling text, and you can pause the display for a set time with a special character - `.

Here's a very short vid just to get a feel on what it looks like, I'll upload something more substantial soon -

There is also a table of colours you can pick from which changes the text colour in real-time, without needing to restart the text animation. I fully intend to do animatable colours, rainbows, etc, plus basic sprite support, and layered graphics for festive visuals.

This whole development came off the back of a long-term desire I've had to produce LED displays (probably going back 5-10 years!), I have also developed a 16x11 flat WS2812 display driven by a Raspberry Pi, written in pure C, with somebody's DMA based library. Yes it can be done on a RasPi, very reliably, without Linux stomping all over the strict timing requirements of WS2812s.

Future developments -

I have some APA102 LED strips I could change to, although I'm not having any real difficulties driving WS2812's, what with their strict requirements, all thanks to the amazing freely available software libraries.

As mentioned, full layered graphics, sprite support (transparency), possibly even a simple web based gameplay element, where players connect to the ESP8266 and play simple games on the display.

I don't have any real plans for adding audio though.

Apologies for not documenting this during the build, but it was hard work as it is without - I do intend on documenting every part of the process though.

Special thanks go out to CNLOHR and others who toiled over the datasheets to give us really easy to use software libraries for driving these LEDs really efficiently, and thanks to the Arduino on ESP8266 community too.


The whole enchilada.

- 16.88 kB - 12/25/2015 at 12:54


  • 1 × ESP8266 ESP-07 Awesome WiFi module of ubiquity
  • 1 × WS2812 Black LED Strip, weather protected Two plus metres of strip off of a single 5M reel.
  • 1 × 3D Printed curved mounting point Matched with the shape of the hat front for a nice curvature and maximum display angle. Only on front half of hat.
  • 1 × El-Cheapo novelty gentlemans hat decorative black ribbon removed.
  • 2 × LM2596S DC-DC Buck converter. Ebay special, Adjustable, 2Amp, max 3Amp.

View all 10 components

  • Building and uploading

    h3liosphan12/25/2015 at 14:29 0 comments

    So you've got the code and the whole build environment is set up and configured.

    Hitting verify (which is really just compile without uploading) gives you a nice output showing you the memory usage of the resulting code, based upon your chip memory -

    Sketch uses 309,476 bytes (71%) of program storage space. Maximum is 434,160 bytes.
    Global variables use 56,616 bytes (69%) of dynamic memory, leaving 25,304 bytes for local variables. Maximum is 81,920 bytes.

    If you try to upload without things connected, and without a USB to serial TTL converter (3.3v compliaint) you'll get this -

    warning: espcomm_sync failed
    error: espcomm_open failed
    So now is time to put everything together. Below is a pic of the wiring for an ESP07 module. Be wary, this is from the underside, so you'll need to carefully mirror every pin horizontally when flipped over.

    For your particular variant, this arrangement of pins will vary wildly. I think you can complete this project with one of the ESP-01 modules, as all we need are -

    • VCC
    • GND
    • TXD
    • RXD
    • REST
    • GPIO2
    • GPIO0
    • GPIO15

    Strictly speaking, GPIO15 is tied to ground on the ESP-01 so all is good here, and the REST pin is tied high to +3.3v I think (thru a resistor?).

    I found a great resource online showing that the boot mode of the ESP is actually controlled with three GPIO pins -

    UART Reflash mode010
    Start running from flash110
    SD Card Boot001

    This says it all, if you're reflashing your ESP, you should tie GPIO0 to ground, and tie GPIO2 to +3.3v. I think I just tied GPIO15 to ground. For my strip perfboard, I wired up an SPDT switch to GND, GPIO0, and +3.3v respectively, so as to control the boot mode, and allow reflashing even when installed in the hat.

    You'll now need the USB to TTL Serial converter dongle. I had a nice 3.3v compliant model.

    You should connect up like so -

    USB To TTL Serial ConverterESP8266 (ESP-07)

    Just tell the Arduino dev environment which COM port your USB to Serial Converter is on, and it should work. You'll see a series of dots appear as it is uploading. Mine filled up one and two third rows with dots before it was finished.

    The program will begin running immediately, but because the data output to the LEDs is on the RXD pin (it uses CNLOHR's I2S implementation, which uses this pin), it won't be going anywhere until you wire it up to your LED strips, and give them some power.

    This does have the effect that the TXD pin on the ESP is still available, hence the Serial Monitor in the IDE environment can update you with debug info if required, even with the LEDs connected - as you can see my code is dotted with serial debug texts.

    Although you've just seen your code run quite nicely if you wire in the WS2812s, if you power cycle the device, it'll not do anything because it's still in bootloader mode. Just flip the switch to run the code.

    This is really all there is to it - that's why I love developing for the ESP8266, due to all the hard work building an Espressif native dev environment in Linux is now unnecessary, it opens the door to really rapid development from a Windows box (or Mac?).

  • Software

    h3liosphan12/25/2015 at 12:54 0 comments

    So this article will go over the basics of the software, although all the real heavy stuff is done inside the various libraries.

    I could do with a little help here actually, as the WiFi code is a little bit unreliable, possibly to do with a relatively large server.send() buffer - please feel free to look over the code and contribute.

    Firstly, Set up your build environment (Arduino 1.6.5) and get together all the various libs. The build and upload parameters are so -

    I have no idea how much Flash memory my particular ESP-07 has, so I just set it to 512K, the lowest. It's currently running at 71% when compiled.

    Notice how the chip is running at 160Mhz - this is double what is recommended, however it seems to work really well.

    Basically just use the boards manager in the Arduino program to grab the ESP8266 build environment - For the record I'm using ESP8266 Community version 1.6.5-947-g39819f0. You may need to point the boards manager to a URL it can fetch the configuration from.

    Also fetch the WS2812 Library from - Add it into the Arduino libraries bit.

    You should then be able to load in the Arduino Sketch and compile it fully.

    Some points of note about the code -

    • If you send a string via a web page form, it'll come out the other end with all spaces changed to + (interestingly not %20) and convert any non alphanumeric chars to a hex code, prefixed with a % char. The plus to space conversion is dead simple. This code below I knocked up quickly to do a simple conversion to a single char from the hex code representation. Because we've still got three chars to convert to a single char, to save mashing the string up I just set a special character of 127 to be a skipping char - the text scroller sees 127 and just moves straight away to the next char.
                    if(*p == '%')
                      *p = 127;   //127 = skip char, see text_scroller()
                      //This is an HTML represented HEX character condition - convert it to the actual character.
                      int rslt = 0;
                      //Convert from Hex String to Int cos there's no avbl library routines I could find that don't hard reset the ESP8266!
                      if(*p > '/' && *p < ':') rslt = 16 * (*p - 48);         // between 0 and 9
                      if(*p > '@' && *p < 'G') rslt = 16 * (*p - 55);         // between A and F
                      *p = 127;
                      if(*p > '/' && *p < ':') rslt += (*p - 48);         // between 0 and 9
                      if(*p > '@' && *p < 'G') rslt += (*p - 55);         // between A and F                
                      Serial.print("output = ");
                      *p = (char)rslt;
      NOTE - I tried to use strtol(), but the Arduino implementation kept killing the ESP for some reason. This code is of course strictly reliant on all chars represented with %hexhex, a single byte, which it will be from a web page, I think!
    • To represent the character set, I wrote a small Windows program which allows you to draw a character in a 7x6 grid, and give you the C code to binary represent it -
      char characters[128][6] = { { 0b01000000, 0b01000000, 0b01000000, 0b00000000, 0b00000000, 0b00000000 },
                { 0b01011111, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000 },
                { 0b00000011, 0b00000000, 0b00000011, 0b00000000, 0b00000000, 0b00000000 },
                { 0b00101000, 0b01111100, 0b00101000, 0b01111100, 0b00101000, 0b00000000 },
                { 0b01001000, 0b01010100, 0b11111110, 0b01010100, 0b00100100, 0b00000000 },
                { 0b01000110, 0b00110000, 0b00001100, 0b01100010, 0b00000000, 0b00000000 },
                { 0b00110100, 0b01001010, 0b01011010, 0b00100100, 0b01000000, 0b00000000 },
                { 0b00000011, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000 },
      I then put together a whole section of the ASCII table in order, for easy referencing when constructing the graphics, currently excludes lower case chars. As can be seen, each line represents a single character, and they're just in a 2d char array. Very simple. Each byte is a vertical stripe of the character, and there are 6 pixels wide, so 6 bytes.
    • There is a function called 'SetupHTMLString()'. This is called in setup() only, it fills a C++ String with the full web page (only...
    Read more »

  • Power calculations?

    h3liosphan12/24/2015 at 22:23 0 comments

    I'm a little surprised right now. I've just done a very simple power calculation for the strips and something is awry. Assuming each LED claims 60mA at full brightness (probably a little lower if driven at 4.2v?), and there are 18 columns by 7 rows.

    This makes 7.56Amps max drain, full white.

    Could this display possibly claim 31.7 watts (4.2v) maximum!?

    I'm not sure how I came to the conclusion that only two of these buck converters are required if they're only rated at 10w, 2 amps (3 maximum).

    Oh well, I guess I shouldn't be driving it at full brightness, but I can get close.

    But even for the really modest power requirements of a simple text scroller, my code currently only drives at half the full brightness (R127 G127 and B127 at white) as it's still really bright because of the dark winter right now! I guess I'll stick to only using 50% of the range throughout.

    At some point I'll do some real power calculations with a test program and an ammeter.

  • Physical Build

    h3liosphan12/24/2015 at 21:35 0 comments

    This bit done most recently, so I'll document it first.

    So here is the all-important interior. From this view, the left of the hat is the front.

    To point out all the bits and pieces, from left to right -

    • The cardboard box the RC battery came in! Strengthened a little with some duct tape, re-openable to replace and recharge the battery, seems to hold it in well. All stuck down with some double sided foam tape.
    • A piece of acrylic sheet, stuck down with more double sided foam tape. It is cut down to size to accommodate the DC-DC buck converters, plus a small strip perfboard with which I mounted the 3.3v regulator, ESP8266, a switch for changing between chip program / run modes, and a 3 pin 0.1" header for programming / driving the LEDs. That's the smallest switch I had!
    • NOTE - The ESP-07 is of course not 0.1" pin pitched, so I ran copper wires from some stripped CAT5 wires and just connected it all up, getting as close as I can to laying it flat against the perfboard without shorting wires.
    • As you can see there's some hot glue residue on the rear wall, this was a failed attempt at mounting the battery on a side wall using some soft material. Turns out it presses against my head when you put it on!
    • Wires all over the place, although I do use connectors instead of permanent solder points wherever possible - I've soldered up things and had to dismantle it again when something goes wrong way too many times!
    • Various RC motor bullet connectors (heat shrink colour coded for + and -) and an XT-60 battery connector. To dismantle the display from the hat, just unplug all the bullet connectors, disconnect the long thin purple data cable, unscrew the two bolts, push in the sides of the hat, and slide the display forward, being careful not to snag the connectors in the holes.

    Why am I using two buck converters? Well because one alone most certainly won't be enough to drive all the LEDs at full brightness, being rated at only 10w each. I power four rows with one, and three rows and the ESP8266 board with the other.

    Point of note - I set the buck converters to provide only 4.2volts. Why? Well because the strips are still awesomely bright when fully illuminated at 4.2v, and it allows the 3.3v data signal to work. Ever since I started working with WS2812s over a year ago, I've tried to drive them at 5v with a 3.3v controller (Raspberry Pi's included), many people say it works, or should work, but for me it hasn't worked (reliably) without some kind of voltage boost on the data signal, usually a Logic Level converter. I've also fallen foul of an initial surge, killing the first or second LEDs in the chain as it turns on at 5v (perhaps surging to 7v or 8v). A bad PSU? Probably, but at 4.2v I've never had to worry about it!

    The bolts were literally hot glued, head first, onto the left and right inside edges of the 3D printed LED mount pointing inwards, then poked through the aforementioned holes. A washer and nut are done up to ensure a tight fit. I took extra care when poking holes in the hat for these attachment points to make sure I got them in the right place.

    There is no connection point on the front of the 3D printed mount, even with the nuts and bolts done up tightly, so it can still rotate up and down a little, kind of like how a helmet visor rotates. This isn't a real problem though as it would only happen when nodding aggressively!

    As for the 3D printed mount, this is literally a 3D model curved around the hat brim, with a 'recess' for putting in the LED strips, and they are spaced vertically to allow a nice line-up pattern of LEDs throughout.

    I used the brilliant Autodesk 123D design program to knock up some half-curve 2D shapes, matched to the curvature of the hat (using trial and error). I produced a thick one and a thin one, then extruded and stacked each at various points vertically, using careful measurements of the 'pixel pitch' to ensure a nice square pixel pitch arrangement. At the top you need to measure it correctly to be vertically stackable... Read more »

View all 4 project logs

Enjoy this project?



Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates