├── settings.h ├── README.md └── ESP8266-WS28xx-Blynk.ino /settings.h: -------------------------------------------------------------------------------- 1 | /************************************************************** 2 | 3 | Settings 4 | 5 | **************************************************************/ 6 | /* 7 | Blynk Auth Code 8 | */ 9 | #define AUTH "8e8bf31a58d843e4bc9daaaa4e7abdfd" 10 | /* 11 | WS28xx Config 12 | */ 13 | 14 | #define LED_TYPE WS2811 15 | #define LED_ARRANGE GRB 16 | #define LED_NUMBER 100 17 | #define LED_LIMIT_MILLIAMPS 2000 // Limit current in mA (Must be using FastLED v3.1.1+) 18 | /* 19 | Zone - Assign a zone to your hardware 20 | -------------------------------------- 21 | In the Blynk App, fill out the Menu Widget at the top with the different 22 | zones you want to control. 23 | Typically this is each room or area so you can control the entire 24 | zone at once, and exclude other zones. Example below: 25 | Zone 0 = reserved (will return nothing as its a false) 26 | Zone 1 = reserved (to control "all" zones at once) 27 | Zone 2 = Office (Menu Widget Item 1) 28 | Zone 3 = Lounge (Menu Widget Item 2) 29 | Zone 4 = Outside (Menu Widget Item 3) 30 | etc.. you can go until your menu widget doesnt let you add more. 31 | -------------------------------------- 32 | */ 33 | #define ZONE 2 34 | /* 35 | Nickname - Unique name for each node 36 | -------------------------------------- 37 | Typically this would be the zone name, followed by the node number. 38 | In my home, I have 2 nodes in each room. So I call them OFFICE1, OFFICE2, LOUNGE1, LOUNGE2. 39 | -------------------------------------- 40 | */ 41 | #define NICKNAME "OFFICE1" 42 | /* 43 | -------------------------------------- 44 | Over The Air Hostname 45 | 46 | I try to use the NICKNAME (above) as the name to identify it in the IDE. 47 | Althought you can use what ever you like. 48 | -------------------------------------- 49 | */ 50 | #define OTA_HOSTNAME "LED-OFFICE1" 51 | /* 52 | Local Server Settings (uncomment to use local server) 53 | */ 54 | #define USE_LOCAL_SERVER 55 | #define SERVER IPAddress(192, 168, 1, 2) 56 | #define BLYNK_MSG_LIMIT 400 57 | /* 58 | Hardware Pins 59 | */ 60 | #define DATA_PIN 12 // GPIO12 / D6 on WeMos/NodeMCU ESP8266 61 | /* 62 | Virtual Pins 63 | */ 64 | #define vPIN_HUE V0 65 | #define vPIN_SATURATION V1 66 | #define vPIN_BRIGHTNESS V2 67 | 68 | #define vPIN_PRESET V3 69 | 70 | #define vPIN_FPS V5 71 | 72 | #define vPIN_COLOUR_BLUE V4 73 | #define vPIN_COLOUR_RED V6 74 | #define vPIN_COLOUR_GREEN V7 75 | #define vPIN_COLOUR_WHITE V8 76 | 77 | #define vPIN_TERMINAL V9 78 | #define vPIN_MANUAL V10 79 | #define vPIN_SYNC_GHUE V11 80 | 81 | #define vPIN_ALERT V13 82 | #define vPIN_OFF V14 83 | 84 | #define vPIN_RAINBOWSPEED V22 85 | #define vPIN_ZONE_SELECT V23 86 | #define vPIN_TESTMODE V24 87 | 88 | #define vPIN_COLOUR_MEM1 V25 89 | #define vPIN_COLOUR_MEM2 V26 90 | #define vPIN_COLOUR_MEM3 V27 91 | #define vPIN_COLOUR_MEMSAVE V28 92 | 93 | #define vPIN_NIGHTMODE V29 94 | /* 95 | 96 | */ 97 | 98 | 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # THIS TUTORIAL IS STILL A WORK IN PROGRESS. SEE THE BLYNK COMMUNITY THREAD BELOW FOR ALL INFO AVAILABLE # 2 | 3 | 4 | # ESP8266-WS2811B-Blynk 5 | An Ardiuno sketch to connect an ESP8266 to WS28xx LED strips and control them using the Blynk mobile app. 6 | This small tutorial will help you build the controller which you can hook up to any number of LEDs you like. (max 2048 I think?) 7 | 8 | Official Blynk Community forum thread: http://community.blynk.cc/t/esp8266-fastled-blynk-smart-shelf-video/7333 9 | 10 | ## Installation 11 | 12 | ### Wifi Credentials 13 | 14 | Create a new folder in your library dir (arduino\libraries\wifi_credentials) called 'wifi_credentials' and create a new file called 'wifi_credentials.h' and copy the example below: 15 | 16 | ```cpp 17 | /* 18 | Wifi Credentials 19 | */ 20 | #ifndef WIFI_CREDS_H 21 | #define WIFI_CREDS_H 22 | #define WIFI_SSID "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 23 | #define WIFI_PASS "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 24 | #endif 25 | ``` 26 | 27 | Replace "xxxxxxx" with your own Wifi network credentials. 28 | 29 | ### Hardware 30 | 31 | * ESP Dev Board. This could be any size or shape as long as it is ***not*** the ESP-01 > ESP-07 varients. 32 | * WS2811/WS2812/WS2812B LEDs. 33 | * High current power supply. (About 1A / meter). 34 | * Small project box. 35 | 36 | ![Smart LED Controller hardware](http://i.imgur.com/jamXAIA.png) 37 | 38 | ### Libraries required: 39 | 40 | * Blynk - http://www.blynk.cc/ 41 | * SimpleTimer - Included in Blynk Library 42 | * FastLED - http://fastled.io/ 43 | * ArduinoOTA (from Arduino IDE Managed Libraries) 44 | 45 | ### Software 46 | 47 | * Download the project INO file and required libraies. 48 | * Download and install the Blynk Mobile App for iOS or Android. 49 | * Create a new project in the Blynk app and email yourself the auto generated auth token. 50 | * Use the QR Code below to clone my Blynk project dashboard. It will require about $4 worth of in-app energy or use a local server where you can give yourself free energy. 51 | * Paste the auth token in to the settings.h file 52 | * Define the number of LEDs you are using. 53 | * If you plan on using more than 1 controller, you can set a nickname for each 54 | ```cpp 55 | char nickname[] = "OFFICE1"; 56 | ``` 57 | * And select it's zone. 58 | * 0 will cause a fatal error 59 | * 1 reserved for ALL zones 60 | * 2 = Menu Widget Item 1 (Modify zone name in Blynk Dash) 61 | * 3 = Menu Widget Item 2 62 | * 4 = Menu Widget Item 3 63 | * 5 = etc etc.. you could make as many zones as the Blynk Menu widget allows. 64 | ```cpp 65 | int HardwareZone = 2; // OFFICE 66 | ``` 67 | 68 | * Upload sketch to your ESP hardware. 69 | ___If you are using ArduinoOTA to update over the network then also set a device hostname and power cycle your hardware after first upload otherwise OTA won't work___ 70 | ```cpp 71 | ArduinoOTA.setHostname("LED-Office1"); 72 | ``` 73 | 74 | ![Blynk Clone Project QR Code](http://i.imgur.com/FW4eFXy.jpg) 75 | 76 | ### Gallery 77 | 78 | #### Video 79 | 80 | [![Smart LED Controller Video](https://img.youtube.com/vi/0lBiOeScbh4/0.jpg)](https://www.youtube.com/watch?v=0lBiOeScbh4) 81 | 82 | #### LED Module 83 | 84 | Here is a little LED light module I buult to put behind items around the house. 85 | I also use this to control strips of LEDs by adding a 3 pin JST connector to the end of the internal LED wiring. 86 | 87 | ![Smart LED Controller running on Blynk](http://community.blynk.cc/uploads/default/optimized/2X/3/3f2e471f2898263a4ee39f464b856228008e9604_1_666x500.jpg) 88 | ![Smart LED Controller running on Blynk](http://community.blynk.cc/uploads/default/optimized/2X/8/86fa4f07ea23d2684375fabe75922a8ec0c000a6_1_375x500.jpg) 89 | ![Smart LED Controller running on Blynk](http://community.blynk.cc/uploads/default/original/2X/4/493706c4a0123c67f99489ad7148b58b17109be2.jpg) 90 | ![Smart LED Controller running on Blynk](http://community.blynk.cc/uploads/default/optimized/2X/5/5f0616484f97dc5e4e3219aff4e08d3272430e8b_1_666x500.jpg) 91 | ![Smart LED Controller running on Blynk](http://community.blynk.cc/uploads/default/optimized/2X/6/6300d2c97a66e285e8275637572b022e97e916c4_1_375x500.jpg) 92 | ![Smart LED Controller running on Blynk](http://community.blynk.cc/uploads/default/optimized/2X/d/d5a41fea209ca08cef209a7a83d4eb8d5dfdb772_1_666x500.jpg) 93 | -------------------------------------------------------------------------------- /ESP8266-WS28xx-Blynk.ino: -------------------------------------------------------------------------------- 1 | #define BLYNK_PRINT Serial 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "settings.h" 8 | 9 | int varSpeed, varRainbowSpeed, varAlertMode, varZone; 10 | int testLEDnumber, varMemSave; 11 | int arrayCurrent[5], arrayMemory1[5], arrayMemory2[5], arrayMemory3[5], arrayNightMemory[5]; 12 | 13 | WidgetTerminal terminal(vPIN_TERMINAL); 14 | BlynkTimer timer; 15 | CRGB leds[LED_NUMBER]; 16 | 17 | void setup() { 18 | WiFi.mode(WIFI_STA); 19 | Serial.begin(115200); 20 | #if defined(USE_LOCAL_SERVER) 21 | Blynk.begin(AUTH, WIFI_SSID, WIFI_PASS, SERVER); 22 | #else 23 | Blynk.begin(AUTH, WIFI_SSID, WIFI_PASS); 24 | #endif 25 | while (Blynk.connect() == false) {} 26 | /*********** OTA *************/ 27 | ArduinoOTA.setHostname(OTA_HOSTNAME); 28 | ArduinoOTA.begin(); 29 | /******** BOOT VARS **********/ 30 | arrayCurrent[0, 255, 255, 255]; // Set starting sequence as rainbow mode 31 | varSpeed = 100; // Start on 100 fps 32 | varZone = 1; 33 | varRainbowSpeed = 0; // Start stationary 34 | /******** FASTLED ************/ 35 | #ifdef LED_LIMIT_MILLIAMPS 36 | FastLED.setMaxPowerInVoltsAndMilliamps(5, LED_LIMIT_MILLIAMPS); 37 | #endif 38 | FastLED.addLeds(leds, LED_NUMBER); 39 | /******** READY **************/ 40 | terminal.print(F("# Blynk v" BLYNK_VERSION ": ")); 41 | terminal.print(NICKNAME); 42 | terminal.println(F(" Device started")); 43 | terminal.flush(); 44 | } 45 | 46 | // List of patterns to cycle through. Each is defined as a separate function below. 47 | typedef void (*SimplePatternList[])(); 48 | SimplePatternList gPatterns = { rainbow, rainbowWithGlitter, confetti, sinelon, juggle}; 49 | uint8_t gCurrentPatternNumber = 0; // Index number of which pattern is current 50 | uint8_t gHue = 0; // rotating "base color" used by many of the patterns 51 | 52 | String CurrentHexRGB() { 53 | return String("#") + String(((long)leds[0].r << 16) | ((long)leds[0].g << 8 ) | (long)leds[0].b, HEX); 54 | } 55 | 56 | BLYNK_WRITE(vPIN_HUE) { 57 | if (varZone == ZONE || varZone == 1) { 58 | updateColours(arrayCurrent[0], param.asInt(), arrayCurrent[2], arrayCurrent[3]); 59 | //Blynk.setProperty(vPIN_HUE, "color", CurrentHexRGB()); 60 | } 61 | } 62 | BLYNK_WRITE(vPIN_SATURATION) { 63 | if (varZone == ZONE || varZone == 1) { 64 | updateColours(arrayCurrent[0], arrayCurrent[1], param.asInt(), arrayCurrent[3]); 65 | //Blynk.setProperty(vPIN_HUE, "color", CurrentHexRGB()); 66 | } 67 | } 68 | BLYNK_WRITE(vPIN_BRIGHTNESS) { 69 | if (varZone == ZONE || varZone == 1) { 70 | updateColours(arrayCurrent[0], arrayCurrent[1], arrayCurrent[2], param.asInt()); 71 | //Blynk.setProperty(vPIN_HUE, "color", CurrentHexRGB()); 72 | } 73 | } 74 | BLYNK_WRITE(vPIN_FPS) { 75 | if (varZone == ZONE || varZone == 1) varSpeed = param.asInt(); 76 | } 77 | BLYNK_WRITE(vPIN_PRESET) { 78 | if (varZone == ZONE || varZone == 1 && param.asInt()) nextPattern(); 79 | } 80 | BLYNK_WRITE(vPIN_COLOUR_RED) { 81 | if (varZone == ZONE || varZone == 1 && param.asInt()) { 82 | updateColours(1, 0, 255, 255); 83 | updateWidgets(); 84 | } 85 | } 86 | BLYNK_WRITE(vPIN_COLOUR_GREEN) { 87 | if (varZone == ZONE || varZone == 1 && param.asInt()) { 88 | updateColours(1, 80, 255, 255); 89 | updateWidgets(); 90 | } 91 | } 92 | BLYNK_WRITE(vPIN_COLOUR_BLUE) { 93 | if (varZone == ZONE || varZone == 1 && param.asInt()) { 94 | updateColours(1, 152, 255, 255); 95 | updateWidgets(); 96 | } 97 | } 98 | BLYNK_WRITE(vPIN_COLOUR_WHITE) { 99 | if (varZone == ZONE || varZone == 1 && param.asInt()) { 100 | updateColours(1, 255, 0, 255); 101 | updateWidgets(); 102 | } 103 | } 104 | BLYNK_WRITE(vPIN_MANUAL) { 105 | if (varZone == ZONE || varZone == 1) { 106 | updateColours(param.asInt(), arrayCurrent[1], arrayCurrent[2], arrayCurrent[3]); 107 | updateWidgets(); 108 | } 109 | } 110 | BLYNK_WRITE(vPIN_SYNC_GHUE) { 111 | gHue = 0; 112 | varSpeed = 100; 113 | terminal.print(NICKNAME); 114 | terminal.println(" | Sync'd gHUE "); 115 | terminal.flush(); 116 | } 117 | BLYNK_WRITE(vPIN_ALERT) { 118 | varAlertMode = param.asInt(); 119 | } 120 | BLYNK_WRITE(vPIN_OFF) { 121 | if ( varZone == ZONE || varZone == 1 && param.asInt()) { 122 | updateColours(1, 255, 255, 0); 123 | updateWidgets(); 124 | } 125 | } 126 | BLYNK_WRITE(vPIN_RAINBOWSPEED) { 127 | if ( varZone == ZONE || varZone == 1) { 128 | varRainbowSpeed = param.asInt(); 129 | Blynk.virtualWrite(vPIN_RAINBOWSPEED, varRainbowSpeed); 130 | } 131 | } 132 | BLYNK_WRITE(vPIN_ZONE_SELECT) { 133 | varZone = param.asInt(); 134 | if (varZone == ZONE) { 135 | terminal.print(NICKNAME); 136 | terminal.println(" | Zone Selected!"); 137 | terminal.flush(); 138 | updateColours(arrayCurrent[0], arrayCurrent[1], arrayCurrent[2], arrayCurrent[3]); 139 | Blynk.virtualWrite(vPIN_FPS, varSpeed); 140 | Blynk.virtualWrite(vPIN_RAINBOWSPEED, varRainbowSpeed); 141 | } 142 | } 143 | BLYNK_WRITE(vPIN_COLOUR_MEM1) { 144 | if (varZone == ZONE || varZone == 1 && param.asInt()) { 145 | if (varMemSave) { 146 | arrayMemory1[arrayCurrent[0], arrayCurrent[1], arrayCurrent[2], arrayCurrent[3]]; 147 | Blynk.setProperty(vPIN_COLOUR_MEM1, "color", CurrentHexRGB()); 148 | } else { 149 | updateColours(arrayMemory1[0], arrayMemory1[1], arrayMemory1[2], arrayMemory1[3]); 150 | updateWidgets(); 151 | } 152 | } 153 | } 154 | BLYNK_WRITE(vPIN_COLOUR_MEM2) { 155 | if (varZone == ZONE || varZone == 1 && param.asInt()) { 156 | if (varMemSave) { 157 | arrayMemory2[arrayCurrent[0], arrayCurrent[1], arrayCurrent[2], arrayCurrent[3]]; 158 | Blynk.setProperty(vPIN_COLOUR_MEM2, "color", CurrentHexRGB()); 159 | } else { 160 | updateColours(arrayMemory2[0], arrayMemory2[1], arrayMemory2[2], arrayMemory2[3]); 161 | updateWidgets(); 162 | } 163 | } 164 | } 165 | BLYNK_WRITE(vPIN_COLOUR_MEM3) { 166 | if ( varZone == ZONE || varZone == 1 && param.asInt()) { 167 | if (varMemSave) { 168 | arrayMemory3[arrayCurrent[0], arrayCurrent[1], arrayCurrent[2], arrayCurrent[3]]; 169 | Blynk.setProperty(vPIN_COLOUR_MEM3, "color", CurrentHexRGB()); 170 | } else { 171 | updateColours(arrayMemory3[0], arrayMemory3[1], arrayMemory3[2], arrayMemory3[3]); 172 | updateWidgets(); 173 | } 174 | } 175 | } 176 | BLYNK_WRITE(vPIN_COLOUR_MEMSAVE) { 177 | varMemSave = param.asInt(); 178 | } 179 | BLYNK_WRITE(vPIN_TESTMODE) { 180 | if (param.asInt()) { 181 | updateColours(2, arrayCurrent[1], arrayCurrent[2], arrayCurrent[3]); 182 | testLEDnumber = param.asInt(); 183 | } else { 184 | updateColours(0, arrayCurrent[1], arrayCurrent[2], arrayCurrent[3]); 185 | } 186 | } 187 | BLYNK_WRITE(vPIN_NIGHTMODE) { 188 | if (param.asInt()) { 189 | arrayNightMemory[arrayCurrent[0], arrayCurrent[1], arrayCurrent[2], arrayCurrent[3]]; 190 | updateColours(1, 152, 255, 100); 191 | updateWidgets(); 192 | } else { 193 | updateColours(arrayNightMemory[0], arrayNightMemory[1], arrayNightMemory[2], arrayNightMemory[3]); 194 | updateWidgets(); 195 | } 196 | } 197 | void updateColours(int m, int h, int s, int b) { 198 | arrayCurrent[0] = m; 199 | arrayCurrent[1] = h; 200 | arrayCurrent[2] = s; 201 | arrayCurrent[3] = b; 202 | } 203 | void updateWidgets() { 204 | Blynk.virtualWrite(vPIN_MANUAL, arrayCurrent[0]); 205 | Blynk.virtualWrite(vPIN_HUE, arrayCurrent[1]); 206 | Blynk.virtualWrite(vPIN_SATURATION, arrayCurrent[2]); 207 | Blynk.virtualWrite(vPIN_BRIGHTNESS, arrayCurrent[3]); 208 | //Blynk.setProperty(vPIN_HUE, "color", CurrentHexRGB()); 209 | } 210 | 211 | /****************************************************************************/ 212 | void loop(){ 213 | Blynk.run(); 214 | ArduinoOTA.handle(); 215 | timer.run(); 216 | 217 | switch (varAlertMode) { 218 | case 1: 219 | for (int i = 0; i < 10; i++) { 220 | fill_solid(leds, LED_NUMBER, CRGB::White); 221 | FastLED.show(); 222 | delay(50); 223 | fill_solid(leds, LED_NUMBER, CRGB::Black); 224 | FastLED.show(); 225 | delay(50); 226 | } 227 | varAlertMode = 0; 228 | break; 229 | case 2: 230 | for (int i = 0; i < 5; i++) { 231 | fill_solid(leds, LED_NUMBER, CRGB::White); 232 | FastLED.show(); 233 | delay(250); 234 | fill_solid(leds, LED_NUMBER, CRGB::Black); 235 | FastLED.show(); 236 | delay(50); 237 | fill_solid(leds, LED_NUMBER, CRGB::White); 238 | FastLED.show(); 239 | delay(50); 240 | fill_solid(leds, LED_NUMBER, CRGB::Black); 241 | FastLED.show(); 242 | delay(250); 243 | } 244 | varAlertMode = 0; 245 | break; 246 | case 3: 247 | for (int i = 0; i < 10; i++) { 248 | fill_solid(leds, LED_NUMBER, CRGB::Blue); 249 | FastLED.show(); 250 | FastLED.delay(50); 251 | fill_solid(leds, LED_NUMBER, CRGB::Red); 252 | FastLED.show(); 253 | FastLED.delay(50); 254 | } 255 | varAlertMode = 0; 256 | break; 257 | case 4: 258 | for (int i = 0; i < 10; i++) { 259 | fill_solid(leds, LED_NUMBER, CRGB::Red); 260 | FastLED.show(); 261 | FastLED.delay(50); 262 | fill_solid(leds, LED_NUMBER, CRGB::Black); 263 | FastLED.show(); 264 | FastLED.delay(50); 265 | } 266 | varAlertMode = 0; 267 | break; 268 | } 269 | 270 | switch (arrayCurrent[0]) { 271 | case 1: 272 | fill_solid(leds, LED_NUMBER, CHSV(arrayCurrent[1], arrayCurrent[2], arrayCurrent[3])); 273 | break; 274 | case 2: 275 | FastLED.clear(); 276 | for (int led = 0; led < testLEDnumber; led++) leds[led] = CRGB::Blue; 277 | break; 278 | default: 279 | gPatterns[gCurrentPatternNumber](); 280 | EVERY_N_MILLISECONDS( 20 ) gHue++; // slowly cycle the "base color" through the rainbow 281 | break; 282 | 283 | } 284 | FastLED.show(); 285 | } 286 | /****************************************************************************/ 287 | #define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0])) 288 | 289 | void nextPattern() { 290 | gCurrentPatternNumber = (gCurrentPatternNumber + 1) % ARRAY_SIZE(gPatterns); 291 | } 292 | 293 | void rainbow() { 294 | // FastLED's built-in rainbow generator 295 | fill_rainbow( leds, LED_NUMBER, gHue, varRainbowSpeed); 296 | FastLED.delay(1000 / varSpeed); 297 | } 298 | 299 | void rainbowWithGlitter() { 300 | // built-in FastLED rainbow, plus some random sparkly glitter 301 | rainbow(); 302 | addGlitter(80); 303 | } 304 | 305 | void addGlitter( fract8 chanceOfGlitter) { 306 | if ( random8() < chanceOfGlitter) leds[ random16(LED_NUMBER) ] += CRGB::White; 307 | FastLED.delay(1000 / varSpeed); 308 | } 309 | 310 | void confetti() { 311 | // random colored speckles that blink in and fade smoothly 312 | fadeToBlackBy( leds, LED_NUMBER, 10); 313 | int pos = random16(LED_NUMBER); 314 | leds[pos] += CHSV( gHue + random8(64), 200, 255); 315 | FastLED.delay(1000 / varSpeed); 316 | } 317 | 318 | void sinelon() { 319 | // a colored dot sweeping back and forth, with fading trails 320 | fadeToBlackBy( leds, LED_NUMBER, 20); 321 | int pos = beatsin16(13, 0, LED_NUMBER); 322 | leds[pos] += CHSV( gHue, 255, 192); 323 | FastLED.delay(1000 / varSpeed); 324 | } 325 | 326 | void juggle() { 327 | // eight colored dots, weaving in and out of sync with each other 328 | fadeToBlackBy( leds, LED_NUMBER, 20); 329 | byte dothue = 0; 330 | for ( int i = 0; i < 8; i++) { 331 | leds[beatsin16(i + 7, 0, LED_NUMBER)] |= CHSV(dothue, 200, 255); 332 | dothue += 32; 333 | } 334 | FastLED.delay(1000 / varSpeed); 335 | } 336 | --------------------------------------------------------------------------------