RGB LED Board for Power Pi 2

LED Board is an ESP8266-based LED driver board for aesthetics, controlled by a web server

Public Chat
Similar projects worth following
In this instance, WS2812 LEDs are mounted on a custom PCB that is held in place by a 3D printed enclosure and linked to an ESP12F board.

The RGB Board's color can be changed by gaining access to the device's IP address and using a webpage to do so.

An ESP8266 board, which is powered by a 5V supply, is driving this RGB LED board.

This RGB LED board is the base for our ongoing project, version 2 of the original Power Pi Project.

This article is about the whole build process of this project, so let's get started with the build.

DESIGN: Power Pi Version 2

We first started out this project by designing the PCB made for the Enclosure.

This project is an extension of another project; this section is a base that contains a RGB LED PCB that glows.

The PCB was modeled such that it could be securely attached using four M2 screws and mounted with the base. The PCB is held in place by four screw bosses.

The RGB LED faces the base portion of the SMD components, which are all installed on the bottom side, including the ESP board. The idea was to print the base part using transparent PLA so that the LED's illumination would fall directly on the inside face of the base, illuminating the entire thing.

The model was finalized and then 3D printed using transparent PLA with a 1mm nozzle and 20% infill.


Regarding the electronics for this project, we needed a microcontroller board with WiFi connectivity because we plan to make an RGB board out of WS2812 LEDs that will be controlled by a Web app.

We use the good old ESP8266 board (the ESP12F to be exact) to drive 16 WS2812 LEDs all connected together.

16 100-nF capacitors were also added between VCC and GND; each LED will have its own 100-nF capacitor for smoothing out the input of the LED.

We will be using 5V as the input power supply, but the ESP8266 is a 3.3V device, which means we had to use the AMS1117 3.3V version to step down 5V into 3.3V for the ESP to work properly without shorting.

The ESP8266 was placed along with a couple of 10K resistors connected to the ESP8266 board according to its minimal configuration.

After finalizing the schematic, we prepare the PCB file using the outline and component positions provided by the CAD design of the board.

The ESP8266 board and other SMD components were positioned close to the bottom of the board, while the RGB LEDs were positioned close to the board's edges.

PCBWAY Service

After completing the PCB design, we export the Gerber data and send it to PCBWAY for samples.

We placed an order for a white silkscreen LED board.

After placing the order, the PCBs were received within a week, and the PCB quality was pretty great.

Over the past ten years, PCBWay has distinguished itself by providing outstanding PCB manufacturing and assembly services, becoming a trusted partner for countless engineers and designers worldwide.

Their commitment to quality and customer satisfaction has been unwavering, leading to significant growth and expansion.

You guys can check out PCBWAY If you want great PCB service at an affordable rate.

LED BOARD v1.f3d

fusion - 177.92 kB - 06/24/2024 at 03:51



Adobe Portable Document Format - 161.65 kB - 06/24/2024 at 03:51


LED BOARD v1.step

step - 189.26 kB - 06/24/2024 at 03:51


  • 1
    PCB Assembly Process
    • Using a solder paste dispensing needle, we first add solder paste to each component pad, one by one. We're using standard 37/63 solder paste here.
    • Next, we pick and place all the SMD components in their places on the PCB using an ESD tweezer.
    • With extreme caution, we lifted the complete circuit board and placed it on the SMT hotplate, which increases the PCB's temperature to the point at which the solder paste melts and all of the components are connected to their pads.
    • At last, we added the THT Tactile Switch in its place and used a soldering iron to solder its pads.

    PCB assembly is now complete.

  • 2
    Flashing the ESP8266-Test Sketch

    To program the ESP12F module, the usual FTDI board method, which requires connecting a flashing button between GPIO 0 and the GND port, is being used.

    We connected the FTDI Board with the ESP Pins according to the below connection.

    • TX of ESP to RX of FTDI
    • RX of ESP to TX of FTDI
    • VCC to 3.3V of ESP
    • GND to GND
    • GPIO 0 to a push switch; the other pin of Flash button is connected with GND

    During uploading, the ESP12F enters programming mode by long-pressing the Flash button first, followed by the reset button.

    Here's an article about programming ESP12F with the FTDI Board for more details:

    Here's the test sketch.

    #include <FastLED.h>
    #define DATA_PIN            14
    #define NUM_LEDS            16
    #define MAX_POWER_MILLIAMPS 500
    #define LED_TYPE            WS2812B
    #define COLOR_ORDER         GRB
    CRGB leds[NUM_LEDS];
    void setup() {
      delay( 3000); // 3 second delay for boot recovery, and a moment of silence
            .setCorrection( TypicalLEDStrip );
      FastLED.setMaxPowerInVoltsAndMilliamps( 5, MAX_POWER_MILLIAMPS);
    void loop()
    // The code for this animation is more complicated than other examples, and 
    // while it is "ready to run", and documented in general, it is probably not 
    // the best starting point for learning.  Nevertheless, it does illustrate some
    // useful techniques.
    // In this animation, there are four "layers" of waves of light.  
    // Each layer moves independently, and each is scaled separately.
    // All four wave layers are added together on top of each other, and then 
    // another filter is applied that adds "whitecaps" of brightness where the 
    // waves line up with each other more.  Finally, another pass is taken
    // over the led array to 'deepen' (dim) the blues and greens.
    // The speed and scale and motion each layer varies slowly within independent 
    // hand-chosen ranges, which is why the code has a lot of low-speed 'beatsin8' functions
    // with a lot of oddly specific numeric ranges.
    // These three custom blue-green color palettes were inspired by the colors found in
    // the waters off the southern coast of California,
    CRGBPalette16 pacifica_palette_1 = 
        { 0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117, 
          0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x14554B, 0x28AA50 };
    CRGBPalette16 pacifica_palette_2 = 
        { 0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117, 
          0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x0C5F52, 0x19BE5F };
    CRGBPalette16 pacifica_palette_3 = 
        { 0x000208, 0x00030E, 0x000514, 0x00061A, 0x000820, 0x000927, 0x000B2D, 0x000C33, 
          0x000E39, 0x001040, 0x001450, 0x001860, 0x001C70, 0x002080, 0x1040BF, 0x2060FF };
    void pacifica_loop()
      // Increment the four "color index start" counters, one for each wave layer.
      // Each is incremented at a different speed, and the speeds vary over time.
      static uint16_t sCIStart1, sCIStart2, sCIStart3, sCIStart4;
      static uint32_t sLastms = 0;
      uint32_t ms = GET_MILLIS();
      uint32_t deltams = ms - sLastms;
      sLastms = ms;
      uint16_t speedfactor1 = beatsin16(3, 179, 269);
      uint16_t speedfactor2 = beatsin16(4, 179, 269);
      uint32_t deltams1 = (deltams * speedfactor1) / 256;
      uint32_t deltams2 = (deltams * speedfactor2) / 256;
      uint32_t deltams21 = (deltams1 + deltams2) / 2;
      sCIStart1 += (deltams1 * beatsin88(1011,10,13));
      sCIStart2 -= (deltams21 * beatsin88(777,8,11));
      sCIStart3 -= (deltams1 * beatsin88(501,5,7));
      sCIStart4 -= (deltams2 * beatsin88(257,4,6));
      // Clear out the LED array to a dim background blue-green
      fill_solid( leds, NUM_LEDS, CRGB( 2, 6, 10));
      // Render each of four layers, with different scales and speeds, that vary over time
      pacifica_one_layer( pacifica_palette_1, sCIStart1, beatsin16( 3, 11 * 256, 14 * 256), beatsin8( 10, 70, 130), 0-beat16( 301) );
      pacifica_one_layer( pacifica_palette_2, sCIStart2, beatsin16( 4,  6 * 256,  9 * 256), beatsin8( 17, 40,  80), beat16( 401) );
      pacifica_one_layer( pacifica_palette_3, sCIStart3, 6 * 256, beatsin8( 9, 10,38), 0-beat16(503));
      pacifica_one_layer( pacifica_palette_3, sCIStart4, 5 * 256, beatsin8( 8, 10,28), beat16(601));
      // Add brighter 'whitecaps' where the waves lines up more
      // Deepen the blues and greens a bit
    // Add one layer of waves into the led array
    void pacifica_one_layer( CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff)
      uint16_t ci = cistart;
      uint16_t waveangle = ioff;
      uint16_t wavescale_half = (wavescale / 2) + 20;
      for( uint16_t i = 0; i < NUM_LEDS; i++) {
        waveangle += 250;
        uint16_t s16 = sin16( waveangle ) + 32768;
        uint16_t cs = scale16( s16 , wavescale_half ) + wavescale_half;
        ci += cs;
        uint16_t sindex16 = sin16( ci) + 32768;
        uint8_t sindex8 = scale16( sindex16, 240);
        CRGB c = ColorFromPalette( p, sindex8, bri, LINEARBLEND);
        leds[i] += c;
    // Add extra 'white' to areas where the four layers of light have lined up brightly
    void pacifica_add_whitecaps()
      uint8_t basethreshold = beatsin8( 9, 55, 65);
      uint8_t wave = beat8( 7 );
      for( uint16_t i = 0; i < NUM_LEDS; i++) {
        uint8_t threshold = scale8( sin8( wave), 20) + basethreshold;
        wave += 7;
        uint8_t l = leds[i].getAverageLight();
        if( l > threshold) {
          uint8_t overage = l - threshold;
          uint8_t overage2 = qadd8( overage, overage);
          leds[i] += CRGB( overage, overage2, qadd8( overage2, overage2));
    // Deepen the blues and greens
    void pacifica_deepen_colors()
      for( uint16_t i = 0; i < NUM_LEDS; i++) {
        leds[i].blue = scale8( leds[i].blue,  145); 
        leds[i].green= scale8( leds[i].green, 200); 
        leds[i] |= CRGB( 2, 5, 7);

    This is an example sketch from the Fast LED Library, which you need to download and install first before uploading this sketch.

  • 3
    Main Sketch

    Using the same FTDI technique, we uploaded the main sketch onto the ESP8266 board after making sure the LEDs were working.

    The primary sketch is a WEBSERVER sketch that allows the user to customize the LED board color by choosing from a broad color palette.

    #include <Adafruit_NeoPixel.h>
    // ESP8266
    #include <ESP8266WiFi.h>
    #include <WiFiClient.h>
    #include <ESP8266WebServer.h>
    #include <ESP8266mDNS.h>
    // Webserver Config
    const char *ssid = "UR SSID";
    const char *password = "UR PASS";
    ESP8266WebServer server ( 80 );
    // Neopixel Config
    #define NeoPIN 14 //GPIOI12
    #define NUM_LEDS 16 //define number of leds in your strip, mine is 18
    int brightness = 250;
    Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, NeoPIN, NEO_RGB + NEO_KHZ800);
    const int led = 13;
    void setup ( void ) {
      Serial.begin ( 115200 );
      // ##############
      // NeoPixel start
      Serial.println("NeoPixel started");
      // #########
      // Webserver
      pinMode ( led, OUTPUT );
      digitalWrite ( led, 0 );
      WiFi.begin ( ssid, password );
      Serial.println ( "" );
      // Wait for connection
      while ( WiFi.status() != WL_CONNECTED ) {
        delay ( 500 );
        Serial.print ( "." );
      Serial.println ( "" );
      Serial.print ( "Connected to " );
      Serial.println ( ssid );
      Serial.print ( "IP address: " );
      Serial.println ( WiFi.localIP() );
      if ( MDNS.begin ( "esp8266" ) ) {
        Serial.println ( "MDNS responder started" );
      // what to do with requests
      server.on ( "/", handleRoot );
      server.onNotFound ( handleNotFound );
      Serial.println ( "HTTP server started" );
    void loop ( void ) {
      // waiting fo a client
    void handleRoot() {
      Serial.println("Client connected");
      digitalWrite ( led, 1 );
      // data from the colorpicker (e.g. #FF00FF)
      String color = server.arg("c");
      Serial.println("Color: " + color);
      // setting the color to the strip 
      // building a website
      char temp[5000];
      int sec = millis() / 1000;
      int min = sec / 60;
      int hr = min / 60;
      char clr [7];
      color.toCharArray(clr, 7);
      snprintf ( temp, 5000,
    "<!DOCTYPE html>\n<html>\n\
        <title>POWER PI 2</title>\n\
          body { background-color: #cccccc; font-family: Arial; Color: #008; }\
        <meta name=\"viewport\" content=\"width=device-width, height=device-height, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0\" />\n\
        <h1>POWER PI RGB BOARD</h1>\n\
        <p>Uptime: %02d:%02d:%02d</p>\n\
        <form action=\"\" name=\"pick\" method=\"post\">\n\
        <input type=\"color\" name=\"c\" value=\"%02d\" onchange=\"document.forms['pick'].submit();\" />\n\
         <span onclick=\"document.forms['pick'].submit();\" style=\"font-size:16pt;\"> CHANGE </span>\n\
        hr, min % 60, sec % 60, clr
      server.send ( 200, "text/html", temp );
      digitalWrite ( led, 0 );
    void handleNotFound() {
      digitalWrite ( led, 1 );
      String message = "File Not Found\n\n";
      message += "URI: ";
      message += server.uri();
      message += "\nMethod: ";
      message += ( server.method() == HTTP_GET ) ? "GET" : "POST";
      message += "\nArguments: ";
      message += server.args();
      message += "\n";
      for ( uint8_t i = 0; i < server.args(); i++ ) {
        message += " " + server.argName ( i ) + ": " + server.arg ( i ) + "\n";
      server.send ( 404, "text/plain", message );
      digitalWrite ( led, 0 );
    void setNeoColor(String value){
      Serial.print("Setting Neopixel...");
      // converting Hex to Int
      int number = (int) strtol( &value[1], NULL, 16);
      // splitting into three parts
      int r = number >> 16;
      int g = number >> 8 & 0xFF;
      int b = number & 0xFF;
      // DEBUG
      Serial.print("RGB: ");
      Serial.print(r, DEC);
      Serial.print(" ");
      Serial.print(g, DEC);
      Serial.print(" ");
      Serial.print(b, DEC);
      Serial.println(" ");
      // setting whole strip to the given color
      for(int i=0; i < NUM_LEDS; i++) {
        strip.setPixelColor(i, strip.Color( g, r, b ) );
      // init;

    Here's how this works: after uploading the sketch, we go to the serial monitor and wait for the ESP to connect with the Wi-Fi router.

    Next, we copy the IP address and input it into a browser that opens the web app.

    The web app lets users pick any color from the color palette provided.

View all 6 instructions

Enjoy this project?



Similar Projects

Does this project spark your interest?

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