├── .DS_Store ├── .gitignore ├── LICENSE ├── README.md ├── Responsive_Led_Control.ino ├── colormodes.h ├── data-moved_aside ├── color-selector.htm ├── graphs.htm └── graphs.js.gz ├── data ├── custom.css ├── edit.htm.gz ├── favicon.ico ├── index.htm.gz ├── jscolor.js.gz ├── offline.appcache └── palettes │ ├── 35_blue_waves.bin │ ├── 37_waves.bin │ ├── Green_White_Red.bin │ ├── Lindaa07.bin │ ├── beading.bin │ ├── bhw1_29.bin │ ├── bhw1_greenie.bin │ ├── bhw1_purpgreen.bin │ ├── bhw1_purplered.bin │ ├── bhw1_sunconure.bin │ ├── bhw2_xmas.bin │ ├── blueeyedgal.bin │ ├── brightsong2.bin │ ├── bud2.bin │ ├── christmas-candy.bin │ ├── faewing3.bin │ ├── goddess-moon.bin │ ├── lkmtch00.bin │ ├── patriot.bin │ ├── plasma.bin │ ├── prism.bin │ ├── sls.bin │ ├── sorcery-2.bin │ ├── starrynite.bin │ ├── twilight.bin │ ├── usa1.bin │ ├── water1.bin │ └── wintercolors.bin ├── definitions.h ├── documentation ├── large.png ├── large50.png ├── small.png └── small50.png ├── eepromsettings.h ├── palette_convert ├── alpen.txt ├── alpen_mango.bin ├── alpen_natural.bin ├── alpen_refuel.bin ├── bhw1_greenie.bin ├── bhw2_23.bin ├── colo_starcrossed.bin ├── colo_tastetherain.bin ├── ggr_blinds.bin ├── ggr_fourbars.bin ├── imagej_edges.bin ├── palette_convert.py └── vredeling_sleep.bin ├── palettes.h ├── request_handlers.h └── spiffs_webserver.h /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | .DS_Store 4 | .DS_Store 5 | upload these via file mgr to ESP8266/.DS_Store 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # doctormord's Responsive Led Control 2 | I mixed the work of [McLighting](https://github.com/toblum/McLighting), [Russell](https://github.com/russp81/LEDLAMP_FASTLEDs) and [Jake's "Grisworld"](https://github.com/jake-b/Griswold-LED-Controller) with [FastLED](https://github.com/FastLED/FastLED) (FastLED library 3.1.3 as of this writing), the colorjs colorpicker, color spectrums created via FastLED Palette Knife, and some additional strip animations (included in the Arduino Sketch above). 3 | 4 | FastLED 3.1.3 library: 5 | https://github.com/FastLED/FastLED 6 | 7 | McLighting library: 8 | https://github.com/toblum/McLighting 9 | 10 | Russel's implementation: 11 | https://github.com/russp81/LEDLAMP_FASTLEDs 12 | 13 | Jakes's "Grisworld" Led Controller 14 | https://github.com/jake-b/Griswold-LED-Controller 15 | 16 | jscolor Color Picker: 17 | http://jscolor.com/ 18 | 19 | FastLED Palette Knife: 20 | http://fastled.io/tools/paletteknife/ 21 | 22 | RemoteDebug: 23 | https://github.com/JoaoLopesF/RemoteDebug 24 | 25 | 26 | If you aren't familiar with how to setup your ESP8266, see the readme on McLighting's git. It's well written and should get you up and running. 27 | 28 | In short you will: 29 | 30 | 1. Configure the Arduino IDE to communicate with the ESP8266 31 | 2. Upload the sketch (from this repo) The sketch is setup for a 120 pixel WS2812B GRB LED Strip. 32 | (change the applicable options in "definitions.h" to your desire) 33 | 3. Patch FastLED Library 34 | 35 | ```arduino 36 | // Note, you need to patch FastLEDs in order to use this. You'll get an 37 | // error related to . Saves more than 3k given the palettes 38 | // 39 | // Simply edit and update the include (Line ~29): 40 | 41 | #if FASTLED_INCLUDE_PGMSPACE == 1 42 | #if (defined(__AVR__)) 43 | #include 44 | #else 45 | #include 46 | #endif 47 | #endif 48 | ``` 49 | 50 | 4. On first launch, the ESP8266 will advertise it's own WiFi network for you to connect to, once you connect to it, launch your browser 51 | and the web interface is self explanatory. (If the interface doesn't load, type in "192.168.4.1" into your browser and hit go) 52 | 5. Once the ESP is on your wifi network, you can then upload the required files for the web interface by typing the in IP address 53 | of the ESP followed by "/edit" (i.e. 192.168.1.20/edit). Then upload the files from the folder labeled "upload these" from this repo. (Or use ESP8266 filesystem uploader, see below) 54 | 6. Once you have finished uploading, type in the IP of the ESP into your browser and you should be up and running! 55 | 56 | Forked from Russel, i removed Adafruit Neopixel references and library calls. 57 | 58 | # Uploading SPIFFS data all at once 59 | 60 | Use ESP8266FS plugin to upload all files from /data to SPIFFS. 61 | 62 | Arduino ESP8266 filesystem uploader 63 | https://github.com/esp8266/arduino-esp8266fs-plugin 64 | 65 | # Improvements/changes so far: 66 | 67 | * new effect: Fire (from WS2812FX) 68 | * new effect: RainbowFire 69 | * new effect: Fireworks [single color, rainbow, random] (from McLightning, ported to used FastLED instead off Adafruit Neopixel) 70 | * new settings for effects in webinterface *.htm 71 | 72 | * speedup the UI alot by pulling the materialize stuff (.css/.js) from server and using .gz compressed files for the rest 73 | * made the UI more responsive with grouped sections and buttons 74 | * added some more palettes 75 | * integrated Arduino OTA 76 | * included setup of LED-count and maximum allowed LED-current to web-interface and EEprom, so different strings don't need changs in source-code 77 | 78 | Large Screen (Desktop) 79 | 80 | ![Large Screen](https://github.com/doctormord/Responsive_LED_Control/raw/master/documentation/large50.png) 81 | 82 | Small Screen (Mobile) 83 | 84 | ![Small Screen](https://github.com/doctormord/Responsive_LED_Control/raw/master/documentation/small50.png) 85 | 86 | 87 | ~~I edited clockless_esp8266.h (in the FastLED platforms folder) and 88 | kept getting flickering until I incremented the WAIT_TIME up to 18us. 89 | (also I did "#define FASTLED_INTERRUPT_RETRY_COUNT 3" inside my sketch).~~ 90 | 91 | For reference, interrupts issue: https://github.com/FastLED/FastLED/issues/306 92 | 93 | # License 94 | 95 | As per the original [McLighting](https://github.com/toblum/McLighting) and [Jake's "Grisworld"](https://github.com/jake-b/Griswold-LED-Controller) project, this project is released under the GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007. 96 | 97 | Griswold is free software: you can redistribute it and/or modify 98 | it under the terms of the GNU Lesser General Public License as 99 | published by the Free Software Foundation, either version 3 of 100 | the License, or (at your option) any later version. 101 | 102 | This program is distributed in the hope that it will be useful, 103 | but WITHOUT ANY WARRANTY; without even the implied warranty of 104 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 105 | GNU General Public License for more details. 106 | 107 | You should have received a copy of the GNU Lesser General Public License 108 | along with this program. If not, see . 109 | 110 | 111 | # Portions of @jake-b "Griswold" LED controller original README 112 | 113 | I bought 1000 WS2811 nodes for my outdoor Christmas light installation this year. 114 | Based on the "Russell's FASTLEDs" project by @russp81, which is in turn based on the "McLighting" project by @toblum 115 | 116 | It seemed necessary to name the thing after Clark Griswold, but really just to differentiate this fork from the originals. 117 | 118 | @russp81 mixed the work of @toblum with the @FastLED (FastLED library 3.1.3 as of this writing), the colorjs colorpicker, color spectrums created via FastLED Palette Knife, and some additional strip animations. 119 | 120 | # Improvements 121 | 122 | - Palettes stored as binary files on SPIFFS. See below for more information on this. 123 | - Display name of the current palette file in the web interface. 124 | - Added ArduinoOTA support so I can update the firmware over WiFi, which will be important when its installed outside. 125 | - Added the ability to store the settings in EEPROM and restore on boot. 126 | - Merged the jscolor interface into the original McLighting interface 127 | - Updated the McLighting interface to retrieve the current settings from the device, and update the UI with the current settings, rather than always default to the defaults. 128 | - General code formatting clean-up. 129 | - Added “RemoteDebug” library for serial console over telnet. (Optional #define) 130 | - Fixed divide-by-zero error that occurs when fps=0 by preventing fps=0 from the UI. 131 | - Updates to the “animated palette” function, now you can select a single palette, or the existing randomized palette after time delay. 132 | - Rearchitected things a bit, now the colormodes.h functions render one single frame, and do not block the main thread. 133 | - Added back the wipe and tv animations from the original McLighting project (removed in LEDLAMP_FASTLEDs) 134 | - Modified TV animation to add some flicker (I like it better) 135 | - Added “effect brightness” setting to allow you to dim the main effect independently of glitter. 136 | 137 | # Palettes on SPIFFS 138 | 139 | Normally, you use [PaletteKnife](http://fastled.io/tools/paletteknife/) to generate arrays with the palette info. You then compile this data into your project. I wanted to be able to update the palettes without recompiling, so I moved them to files in SPIFFS (/palettes directory). There is a little python program that basically takes the logic from PaletteKnife and outputs a binary file with the palette data instead. Load these binary files to SPIFFS using the [Arduino ESP8266 filesystem uploader](https://github.com/esp8266/arduino-esp8266fs-plugin) or manually. 140 | -------------------------------------------------------------------------------- /Responsive_Led_Control.ino: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 @doctormord @jake-b, @russp81, @toblum 2 | // Responsive LED Control 3 | 4 | // This is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of 7 | // the License, or (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU Lesser General Public License 15 | // along with this program. If not, see . 16 | 17 | // Griswold is a fork of the LEDLAMP project at 18 | // https://github.com/russp81/LEDLAMP_FASTLEDs 19 | 20 | // The LEDLAMP project is a fork of the McLighting Project at 21 | // https://github.com/toblum/McLighting 22 | 23 | // *************************************************************************** 24 | // Load libraries for: WebServer / WiFiManager / WebSockets 25 | // *************************************************************************** 26 | #include //https://github.com/esp8266/Arduino 27 | 28 | // needed for library WiFiManager 29 | #include 30 | #include 31 | #include //https://github.com/tzapu/WiFiManager 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | //#include "RemoteDebug.h" //https://github.com/JoaoLopesF/RemoteDebug 40 | 41 | #include //https://github.com/Links2004/arduinoWebSockets 42 | #include 43 | 44 | // *************************************************************************** 45 | // Sub-modules of this application 46 | // *************************************************************************** 47 | #include "definitions.h" 48 | #include "eepromsettings.h" 49 | #include "palettes.h" 50 | #include "colormodes.h" 51 | 52 | // *************************************************************************** 53 | // Instanciate HTTP(80) / WebSockets(81) Server 54 | // *************************************************************************** 55 | ESP8266WebServer server(80); 56 | WebSocketsServer webSocket = WebSocketsServer(81); 57 | 58 | // *************************************************************************** 59 | // Load library "ticker" for blinking status led 60 | // *************************************************************************** 61 | Ticker ticker; 62 | 63 | void tick() { 64 | // toggle state 65 | int state = digitalRead(LED_BUILTIN); // get the current state of GPIO1 pin 66 | digitalWrite(LED_BUILTIN, !state); // set pin to the opposite state 67 | } 68 | 69 | // *************************************************************************** 70 | // Callback for WiFiManager library when config mode is entered 71 | // *************************************************************************** 72 | // gets called when WiFiManager enters configuration mode 73 | void configModeCallback(WiFiManager *myWiFiManager) { 74 | DBG_OUTPUT_PORT.println("Entered config mode"); 75 | DBG_OUTPUT_PORT.println(WiFi.softAPIP()); 76 | // if you used auto generated SSID, print it 77 | DBG_OUTPUT_PORT.println(myWiFiManager->getConfigPortalSSID()); 78 | // entered config mode, make led toggle faster 79 | ticker.attach(0.2, tick); 80 | 81 | // Show USER that module can't connect to stored WiFi 82 | uint16_t i; 83 | for (i = 0; i < 2; i++) { 84 | leds[i].setRGB(0, 0, 50); 85 | } 86 | FastLED.show(); 87 | } 88 | 89 | // *************************************************************************** 90 | // Include: Webserver & Request Handlers 91 | // *************************************************************************** 92 | #include "spiffs_webserver.h" // must be included after the 'server' object 93 | #include "request_handlers.h" // is declared. 94 | 95 | // *************************************************************************** 96 | // MAIN 97 | // *************************************************************************** 98 | void setup() { 99 | 100 | // Generate a pseduo-unique hostname 101 | char hostname[strlen(HOSTNAME_PREFIX)+6]; 102 | uint16_t chipid = ESP.getChipId() & 0xFFFF; 103 | sprintf(hostname, "%s-%04x",HOSTNAME_PREFIX, chipid); 104 | 105 | #ifdef REMOTE_DEBUG 106 | Debug.begin(hostname); // Initiaze the telnet server - hostname is the used 107 | // in MDNS.begin 108 | Debug.setResetCmdEnabled(true); // Enable the reset command 109 | #endif 110 | 111 | // *************************************************************************** 112 | // Setup: EEPROM 113 | // *************************************************************************** 114 | initSettings(); // setting loaded from EEPROM or defaults if fail 115 | printSettings(); 116 | 117 | ///*** Random Seed*** 118 | randomSeed(analogRead(0)); 119 | 120 | //********color palette setup stuff**************** 121 | currentPalette = RainbowColors_p; 122 | loadPaletteFromFile(settings.palette_ndx, &targetPalette); 123 | currentBlending = LINEARBLEND; 124 | //************************************************** 125 | 126 | #ifndef REMOTE_DEBUG 127 | DBG_OUTPUT_PORT.begin(115200); 128 | #endif 129 | DBG_OUTPUT_PORT.printf("system_get_cpu_freq: %d\n", system_get_cpu_freq()); 130 | 131 | // set builtin led pin as output 132 | pinMode(LED_BUILTIN, OUTPUT); 133 | // start ticker with 0.5 because we start in AP mode and try to connect 134 | ticker.attach(0.5, tick); 135 | 136 | // *************************************************************************** 137 | // Setup: FASTLED 138 | // *************************************************************************** 139 | delay(500); // 500ms delay for recovery 140 | 141 | // limit my draw to 2.1A at 5v of power draw 142 | FastLED.setMaxPowerInVoltsAndMilliamps(5,settings.max_current); 143 | 144 | // maximum refresh rate 145 | FastLED.setMaxRefreshRate(FASTLED_HZ); 146 | 147 | // tell FastLED about the LED strip configuration 148 | FastLED.addLeds(leds, settings.num_leds) 149 | .setCorrection(TypicalLEDStrip); 150 | 151 | // FastLED.addLeds(leds, 152 | // NUM_LEDS).setCorrection(TypicalLEDStrip); 153 | // set master brightness control 154 | FastLED.setBrightness(settings.overall_brightness); 155 | 156 | 157 | // *************************************************************************** 158 | // Setup: WiFiManager 159 | // *************************************************************************** 160 | // Local intialization. Once its business is done, there is no need to keep it 161 | // around 162 | WiFiManager wifiManager; 163 | // reset settings - for testing 164 | // wifiManager.resetSettings(); 165 | 166 | //sets timeout until configuration portal gets turned off 167 | //useful to make it all retry or go to sleep 168 | //in seconds 169 | wifiManager.setTimeout(20); 170 | wifiManager.setBreakAfterConfig(true); 171 | 172 | // set callback that gets called when connecting to previous WiFi fails, and 173 | // enters Access Point mode 174 | wifiManager.setAPCallback(configModeCallback); 175 | 176 | 177 | // fetches ssid and pass and tries to connect 178 | // if it does not connect it starts an access point with the specified name 179 | // here "AutoConnectAP" 180 | // and goes into a blocking loop awaiting configuration 181 | 182 | if (!wifiManager.autoConnect(hostname)) { 183 | DBG_OUTPUT_PORT.println("failed to connect and hit timeout"); 184 | DBG_OUTPUT_PORT.println("No connection made, loading last saved show parameters.."); 185 | WiFi.forceSleepBegin(); // power down WiFi, as it is not needed anymore. 186 | } 187 | 188 | // if you get here you have connected to the WiFi 189 | DBG_OUTPUT_PORT.println("get the show started.. :)"); 190 | ticker.detach(); 191 | // keep LED on 192 | digitalWrite(LED_BUILTIN, LOW); 193 | 194 | // *************************************************************************** 195 | // Setup: ArduinoOTA 196 | // *************************************************************************** 197 | ArduinoOTA.setHostname(hostname); 198 | ArduinoOTA.onStart([]() { 199 | 200 | String type; 201 | // if (ArduinoOTA.getCommand() == U_FLASH) 202 | // type = "sketch"; 203 | // else 204 | // type = "filesystem"; 205 | // 206 | SPIFFS.end(); // unmount SPIFFS for update. 207 | // DBG_OUTPUT_PORT.println("Start updating " + type); 208 | DBG_OUTPUT_PORT.println("Start updating "); 209 | }); 210 | ArduinoOTA.onEnd([]() { 211 | DBG_OUTPUT_PORT.println("\nEnd... remounting SPIFFS"); 212 | SPIFFS.begin(); 213 | paletteCount = getPaletteCount(); 214 | }); 215 | ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { 216 | DBG_OUTPUT_PORT.printf("Progress: %u%%\r", (progress / (total / 100))); 217 | }); 218 | ArduinoOTA.onError([](ota_error_t error) { 219 | DBG_OUTPUT_PORT.printf("Error[%u]: ", error); 220 | if (error == OTA_AUTH_ERROR) 221 | DBG_OUTPUT_PORT.println("Auth Failed"); 222 | else if (error == OTA_BEGIN_ERROR) 223 | DBG_OUTPUT_PORT.println("Begin Failed"); 224 | else if (error == OTA_CONNECT_ERROR) 225 | DBG_OUTPUT_PORT.println("Connect Failed"); 226 | else if (error == OTA_RECEIVE_ERROR) 227 | DBG_OUTPUT_PORT.println("Receive Failed"); 228 | else if (error == OTA_END_ERROR) 229 | DBG_OUTPUT_PORT.println("End Failed"); 230 | }); 231 | 232 | ArduinoOTA.begin(); 233 | DBG_OUTPUT_PORT.println("OTA Ready"); 234 | DBG_OUTPUT_PORT.print("IP address: "); 235 | DBG_OUTPUT_PORT.println(WiFi.localIP()); 236 | 237 | 238 | // *************************************************************************** 239 | // Setup: MDNS responder 240 | // *************************************************************************** 241 | MDNS.begin(hostname); 242 | DBG_OUTPUT_PORT.print("Open http://"); 243 | DBG_OUTPUT_PORT.print(hostname); 244 | DBG_OUTPUT_PORT.println(".local/edit to see the file browser"); 245 | 246 | // *************************************************************************** 247 | // Setup: WebSocket server 248 | // *************************************************************************** 249 | webSocket.begin(); 250 | webSocket.onEvent(webSocketEvent); 251 | 252 | // *************************************************************************** 253 | // Setup: SPIFFS 254 | // *************************************************************************** 255 | SPIFFS.begin(); 256 | { 257 | Dir dir = SPIFFS.openDir("/"); 258 | while (dir.next()) { 259 | String fileName = dir.fileName(); 260 | size_t fileSize = dir.fileSize(); 261 | DBG_OUTPUT_PORT.printf("FS File: %s, size: %s\n", fileName.c_str(), 262 | formatBytes(fileSize).c_str()); 263 | } 264 | DBG_OUTPUT_PORT.printf("\n"); 265 | } 266 | 267 | // *************************************************************************** 268 | // Setup: SPIFFS Webserver handler 269 | // *************************************************************************** 270 | 271 | // list directory 272 | server.on("/list", HTTP_GET, handleFileList); 273 | 274 | // load editor 275 | server.on("/edit", HTTP_GET, []() { 276 | if (!handleFileRead("/edit.htm")) 277 | server.send(404, "text/plain", "FileNotFound"); 278 | }); 279 | 280 | // create file 281 | server.on("/edit", HTTP_PUT, handleFileCreate); 282 | 283 | // delete file 284 | server.on("/edit", HTTP_DELETE, handleFileDelete); 285 | 286 | // first callback is called after the request has ended with all parsed 287 | // arguments 288 | // second callback handles file uploads at that location 289 | server.on("/edit", HTTP_POST, []() { server.send(200, "text/plain", ""); }, 290 | handleFileUpload); 291 | 292 | // get heap status, analog input value and all GPIO statuses in one json call 293 | server.on("/esp_status", HTTP_GET, []() { 294 | String json = "{"; 295 | json += "\"heap\":" + String(ESP.getFreeHeap()); 296 | json += ", \"analog\":" + String(analogRead(A0)); 297 | json += ", \"gpio\":" + 298 | String((uint32_t)(((GPI | GPO) & 0xFFFF) | ((GP16I & 0x01) << 16))); 299 | json += "}"; 300 | server.send(200, "text/json", json); 301 | json = String(); 302 | }); 303 | 304 | // called when the url is not defined here 305 | // use it to load content from SPIFFS 306 | server.onNotFound([]() { 307 | if (!handleFileRead(server.uri())) handleNotFound(); 308 | }); 309 | 310 | server.on("/upload", handleMinimalUpload); 311 | 312 | server.on("/restart", []() { 313 | DBG_OUTPUT_PORT.printf("/restart:\n"); 314 | server.send(200, "text/plain", "restarting..."); 315 | ESP.restart(); 316 | }); 317 | 318 | server.on("/reset_wlan", []() { 319 | DBG_OUTPUT_PORT.printf("/reset_wlan:\n"); 320 | server.send(200, "text/plain", "Resetting WLAN and restarting..."); 321 | WiFiManager wifiManager; 322 | wifiManager.resetSettings(); 323 | ESP.restart(); 324 | }); 325 | 326 | // *************************************************************************** 327 | // Setup: SPIFFS Webserver handler 328 | // *************************************************************************** 329 | server.on("/set_brightness", []() { 330 | if (server.arg("c").toInt() > 0) { 331 | settings.overall_brightness = (int)server.arg("c").toInt() * 2.55; 332 | } else { 333 | settings.overall_brightness = server.arg("p").toInt(); 334 | } 335 | if (settings.overall_brightness > 255) { 336 | settings.overall_brightness = 255; 337 | } 338 | if (settings.overall_brightness < 0) { 339 | settings.overall_brightness = 0; 340 | } 341 | FastLED.setBrightness(settings.overall_brightness); 342 | 343 | if (settings.mode == HOLD) { 344 | settings.mode = ALL; 345 | } 346 | 347 | getStatusJSON(); 348 | }); 349 | 350 | server.on("/get_brightness", []() { 351 | String str_brightness = String((int)(settings.overall_brightness / 2.55)); 352 | server.send(200, "text/plain", str_brightness); 353 | DBG_OUTPUT_PORT.print("/get_brightness: "); 354 | DBG_OUTPUT_PORT.println(str_brightness); 355 | }); 356 | 357 | server.on("/get_switch", []() { 358 | server.send(200, "text/plain", (settings.mode == OFF) ? "0" : "1"); 359 | DBG_OUTPUT_PORT.printf("/get_switch: %s\n", 360 | (settings.mode == OFF) ? "0" : "1"); 361 | }); 362 | 363 | server.on("/get_color", []() { 364 | String rgbcolor = String(settings.main_color.red, HEX) + 365 | String(settings.main_color.green, HEX) + 366 | String(settings.main_color.blue, HEX); 367 | server.send(200, "text/plain", rgbcolor); 368 | DBG_OUTPUT_PORT.print("/get_color: "); 369 | DBG_OUTPUT_PORT.println(rgbcolor); 370 | }); 371 | 372 | server.on("/status", []() { getStatusJSON(); }); 373 | 374 | server.on("/off", []() { 375 | //exit_func = true; 376 | settings.mode = OFF; 377 | getArgs(); 378 | getStatusJSON(); 379 | }); 380 | 381 | server.on("/all", []() { 382 | //exit_func = true; 383 | settings.mode = ALL; 384 | getArgs(); 385 | getStatusJSON(); 386 | }); 387 | 388 | server.on("/rainbow", []() { 389 | //exit_func = true; 390 | settings.mode = RAINBOW; 391 | getArgs(); 392 | getStatusJSON(); 393 | }); 394 | 395 | server.on("/confetti", []() { 396 | //exit_func = true; 397 | settings.mode = CONFETTI; 398 | getArgs(); 399 | getStatusJSON(); 400 | }); 401 | 402 | server.on("/sinelon", []() { 403 | //exit_func = true; 404 | settings.mode = SINELON; 405 | getArgs(); 406 | getStatusJSON(); 407 | }); 408 | 409 | server.on("/juggle", []() { 410 | //exit_func = true; 411 | settings.mode = JUGGLE; 412 | getArgs(); 413 | getStatusJSON(); 414 | }); 415 | 416 | server.on("/bpm", []() { 417 | //exit_func = true; 418 | settings.mode = BPM; 419 | getArgs(); 420 | getStatusJSON(); 421 | }); 422 | 423 | server.on("/ripple", []() { 424 | //exit_func = true; 425 | settings.mode = RIPPLE; 426 | getArgs(); 427 | getStatusJSON(); 428 | }); 429 | 430 | server.on("/comet", []() { 431 | //exit_func = true; 432 | settings.mode = COMET; 433 | getArgs(); 434 | getStatusJSON(); 435 | }); 436 | 437 | server.on("/wipe", []() { 438 | settings.mode = WIPE; 439 | getArgs(); 440 | getStatusJSON(); 441 | }); 442 | 443 | server.on("/tv", []() { 444 | settings.mode = TV; 445 | getArgs(); 446 | getStatusJSON(); 447 | }); 448 | 449 | server.on("/fire", []() { 450 | //exit_func = true; 451 | settings.mode = FIRE; 452 | getArgs(); 453 | getStatusJSON(); 454 | }); 455 | 456 | server.on("/frainbow", []() { 457 | //exit_func = true; 458 | settings.mode = FIRE_RAINBOW; 459 | getArgs(); 460 | getStatusJSON(); 461 | }); 462 | 463 | server.on("/fworks", []() { 464 | //exit_func = true; 465 | settings.mode = FIREWORKS; 466 | getArgs(); 467 | getStatusJSON(); 468 | }); 469 | 470 | server.on("/fwsingle", []() { 471 | //exit_func = true; 472 | settings.mode = FIREWORKS_SINGLE; 473 | getArgs(); 474 | getStatusJSON(); 475 | }); 476 | 477 | server.on("/fwrainbow", []() { 478 | //exit_func = true; 479 | settings.mode = FIREWORKS_RAINBOW; 480 | getArgs(); 481 | getStatusJSON(); 482 | }); 483 | 484 | server.on("/palette_anims", []() { 485 | settings.mode = PALETTE_ANIMS; 486 | if (server.arg("p") != "") { 487 | uint8_t pal = (uint8_t) strtol(server.arg("p").c_str(), NULL, 10); 488 | if (pal > paletteCount) 489 | pal = paletteCount; 490 | 491 | settings.palette_ndx = pal; 492 | loadPaletteFromFile(settings.palette_ndx, &targetPalette); 493 | currentPalette = targetPalette; //PaletteCollection[settings.palette_ndx]; 494 | DBG_OUTPUT_PORT.printf("Palette is: %d", pal); 495 | } 496 | getStatusJSON(); 497 | }); 498 | 499 | server.begin(); 500 | 501 | paletteCount = getPaletteCount(); 502 | } 503 | 504 | 505 | 506 | void loop() { 507 | EVERY_N_MILLISECONDS(int(float(1000 / settings.fps))) { 508 | gHue++; // slowly cycle the "base color" through the rainbow 509 | } 510 | 511 | // adjust LED current to actual value; 512 | FastLED.setMaxPowerInVoltsAndMilliamps(5,settings.max_current); 513 | 514 | // Simple statemachine that handles the different modes 515 | switch (settings.mode) { 516 | default: 517 | case OFF: 518 | fill_solid(leds, settings.num_leds, CRGB(0,0,0)); 519 | break; 520 | 521 | case ALL: 522 | fill_solid(leds, settings.num_leds, CRGB(settings.main_color.red, settings.main_color.green, 523 | settings.main_color.blue)); 524 | break; 525 | 526 | case MIXEDSHOW: 527 | { 528 | gPatterns[gCurrentPatternNumber](); 529 | 530 | // send the 'leds' array out to the actual LED strip 531 | int showlength_Millis = settings.show_length * 1000; 532 | 533 | // DBG_OUTPUT_PORT.println("showlengthmillis = " + 534 | // String(showlength_Millis)); 535 | if (((millis()) - (lastMillis)) >= showlength_Millis) { 536 | nextPattern(); 537 | DBG_OUTPUT_PORT.println( "void nextPattern was called at " + String(millis()) + 538 | " and the current show length set to " + String(showlength_Millis)); 539 | } 540 | } 541 | break; 542 | 543 | case RAINBOW: 544 | rainbow(); 545 | break; 546 | 547 | case CONFETTI: 548 | confetti(); 549 | break; 550 | 551 | case SINELON: 552 | sinelon(); 553 | break; 554 | 555 | case JUGGLE: 556 | juggle(); 557 | break; 558 | 559 | case BPM: 560 | bpm(); 561 | break; 562 | 563 | case PALETTE_ANIMS: 564 | palette_anims(); 565 | break; 566 | 567 | case RIPPLE: 568 | ripple(); 569 | break; 570 | 571 | case COMET: 572 | comet(); 573 | break; 574 | 575 | case THEATERCHASE: 576 | theaterChase(); 577 | break; 578 | 579 | case WIPE: 580 | colorWipe(); 581 | break; 582 | 583 | case TV: 584 | tv(); 585 | break; 586 | 587 | case FIRE: 588 | fire2012(); 589 | break; 590 | 591 | case FIRE_RAINBOW: 592 | fire_rainbow(); 593 | break; 594 | 595 | case FIREWORKS: 596 | fireworks(); 597 | break; 598 | 599 | case FIREWORKS_SINGLE: 600 | fw_single(); 601 | break; 602 | 603 | case FIREWORKS_RAINBOW: 604 | fw_rainbow(); 605 | break; 606 | } 607 | 608 | // Add glitter if necessary 609 | if (settings.glitter_on == true) { 610 | addGlitter(settings.glitter_density); 611 | } 612 | 613 | // Get the current time 614 | unsigned long continueTime = millis() + int(float(1000 / settings.fps)); 615 | // Do our main loop functions, until we hit our wait time 616 | 617 | do { 618 | //long int now = micros(); 619 | FastLED.show(); // Display whats rendered. 620 | //long int later = micros(); 621 | //DBG_OUTPUT_PORT.printf("Show time is %ld\n", later-now); 622 | server.handleClient(); // Handle requests to the web server 623 | webSocket.loop(); // Handle websocket traffic 624 | ArduinoOTA.handle(); // Handle OTA requests. 625 | #ifdef REMOTE_DEBUG 626 | Debug.handle(); // Handle telnet server 627 | #endif 628 | yield(); // Yield for ESP8266 stuff 629 | 630 | if (WiFi.status() != WL_CONNECTED) { 631 | // Blink the LED quickly to indicate WiFi connection lost. 632 | ticker.attach(0.1, tick); 633 | 634 | //EVERY_N_MILLISECONDS(1000) { 635 | // int state = digitalRead(LED_BUILTIN); // get the current state of GPIO1 pin 636 | // digitalWrite(LED_BUILTIN, !state); 637 | // } 638 | } else { 639 | ticker.detach(); 640 | // Light on-steady indicating WiFi is connected. 641 | //digitalWrite(LED_BUILTIN, false); 642 | } 643 | 644 | } while (millis() < continueTime); 645 | 646 | 647 | } 648 | 649 | void nextPattern() { 650 | // add one to the current pattern number, and wrap around at the end 651 | // gCurrentPatternNumber = (gCurrentPatternNumber + random(0, 652 | // ARRAY_SIZE(gPatterns))) % ARRAY_SIZE( gPatterns); 653 | gCurrentPatternNumber = random(0, ARRAY_SIZE(gPatterns)); 654 | lastMillis = millis(); 655 | } 656 | -------------------------------------------------------------------------------- /colormodes.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 @jake-b, @russp81, @toblum 2 | // Griswold LED Lighting Controller 3 | 4 | // Griswold is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of 7 | // the License, or (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU Lesser General Public License 15 | // along with this program. If not, see . 16 | 17 | // Griswold is a fork of the LEDLAMP project at 18 | // https://github.com/russp81/LEDLAMP_FASTLEDs 19 | 20 | // The LEDLAMP project is a fork of the McLighting Project at 21 | // https://github.com/toblum/McLighting 22 | 23 | // *************************************************************************** 24 | // Color modes 25 | // *************************************************************************** 26 | //#include "definitions.h" 27 | 28 | char* listStatusJSON(); 29 | 30 | extern WebSocketsServer webSocket; 31 | 32 | // These functions originally displayed the color using a call to FastLed.show() 33 | // This has been refactored out, theser functions now simply render into the 34 | // leds[] array. The FastLed.show() call happens in the main loop now. 35 | // Furthermore, the 'add glitter' option also refactored out to the main loop. 36 | 37 | void addGlitter(fract8 chanceOfGlitter) { 38 | if (random8() < chanceOfGlitter) { 39 | leds[random16(settings.num_leds)] += 40 | CRGB(settings.glitter_color.red, settings.glitter_color.green, 41 | settings.glitter_color.blue); 42 | } 43 | } 44 | 45 | void rainbow() { 46 | // FastLED's built-in rainbow generator 47 | fill_rainbow(leds, settings.num_leds, gHue, 7); 48 | 49 | // if (settings.glitter_on == true){addGlitter(settings.glitter_density);} 50 | // frame has been created, now show it 51 | // FastLED.show(); 52 | // insert a delay to keep the framerate modest 53 | // FastLED.delay(int(float(500/settings.fps))); 54 | } 55 | 56 | void confetti() { 57 | // random colored speckles that blink in and fade smoothly 58 | fadeToBlackBy(leds, settings.num_leds, settings.ftb_speed); 59 | for (int x=0; x endingLEDIndex) return; //stop condition 124 | 125 | // leds[i] = ColorFromPalette( currentPalette, colorIndex + sin8(i*16), 126 | // brightness); 127 | leds[i] = ColorFromPalette(palette, colorIndex, 128 | settings.effect_brightness); 129 | if (anim_direction == FORWARD) { 130 | colorIndex += 3; 131 | } 132 | if (anim_direction == BACK) { 133 | colorIndex -= 3; 134 | } 135 | } 136 | } 137 | 138 | void ChangePalettePeriodically(bool forceNow) { 139 | if (forceNow || millis() - paletteMillis > (settings.show_length * 1000)) { 140 | paletteMillis = millis(); 141 | 142 | targetPaletteIndex = random(0, paletteCount); 143 | 144 | currentPalette = targetPalette; 145 | 146 | anim_direction = (DIRECTION)!anim_direction; // DIRECTION enum allows flipping by boolean not. 147 | 148 | loadPaletteFromFile(targetPaletteIndex, &targetPalette); 149 | 150 | DBG_OUTPUT_PORT.printf("New pallet index: %d\n", targetPaletteIndex); 151 | 152 | if (settings.glitter_wipe_on) { 153 | DBG_OUTPUT_PORT.println("Begin glitter wipe"); 154 | wipeInProgress = true; 155 | } 156 | } 157 | } 158 | 159 | void colorWipe() { 160 | static CRGB prevColor = CHSV(gHue, 255, settings.effect_brightness); 161 | static CRGB currentColor = CHSV(gHue+60, 255, settings.effect_brightness); 162 | 163 | // Wrap around if necessary 164 | if (wipePos >= settings.num_leds) { 165 | wipePos = 0; 166 | prevColor = currentColor; 167 | gHue += 60; 168 | currentColor = CHSV(gHue, 255, settings.effect_brightness); 169 | } 170 | 171 | // Render the first half of the wipe 172 | for (int x=0; x= 0 && speckle < settings.num_leds) { 185 | leds[speckle] += CRGB(settings.glitter_color.red, settings.glitter_color.green, 186 | settings.glitter_color.blue); 187 | } 188 | } 189 | } 190 | 191 | // Advance for next frame 192 | wipePos+=WIPE_SPEED; 193 | } 194 | 195 | void palette_anims() { 196 | currentBlending = LINEARBLEND; 197 | 198 | if (settings.palette_ndx == -1) ChangePalettePeriodically(false); 199 | 200 | if (!settings.glitter_wipe_on) { 201 | uint8_t maxChanges = int(float(settings.fps / 2)); 202 | nblendPaletteTowardPalette(currentPalette, targetPalette, maxChanges); 203 | 204 | // Update the current palette if necessary-- and send to any connected clients. 205 | if (currentPaletteIndex != targetPaletteIndex) { 206 | currentPaletteIndex = targetPaletteIndex; 207 | 208 | // Send current palette name to the UI. 209 | String name = getPaletteNameWithIndex(currentPaletteIndex); 210 | webSocket.broadcastTXT("p"+name); 211 | } 212 | } 213 | 214 | static uint8_t startIndex = 0; 215 | 216 | /* motion speed */ 217 | startIndex = startIndex + 3; 218 | 219 | FillLEDsFromPaletteColors(currentPalette,startIndex); 220 | 221 | if (settings.glitter_wipe_on && wipeInProgress) { 222 | if (wipePos >= settings.num_leds) { 223 | DBG_OUTPUT_PORT.println("End glitter wipe"); 224 | wipeInProgress = false; 225 | wipePos = 0; 226 | currentPalette = targetPalette; 227 | currentPaletteIndex = targetPaletteIndex; 228 | 229 | // Send current palette name to the UI. 230 | String name = getPaletteNameWithIndex(currentPaletteIndex); 231 | webSocket.broadcastTXT("p"+name); 232 | FillLEDsFromPaletteColors(targetPalette,startIndex); 233 | } else { 234 | FillLEDsFromPaletteColors(targetPalette,startIndex, wipePos); 235 | for (int x=0; x < 3; x++) { 236 | int speckle = wipePos + random(-SPARKLE_SPREAD,SPARKLE_SPREAD); 237 | if (speckle >= 0 && speckle < settings.num_leds) { 238 | leds[speckle] += CRGB(settings.glitter_color.red, settings.glitter_color.green, 239 | settings.glitter_color.blue); 240 | } 241 | } 242 | wipePos+=WIPE_SPEED; 243 | } 244 | } 245 | 246 | 247 | } 248 | 249 | //*****************LED RIPPLE***************************************************** 250 | 251 | void one_color_allHSV(int ahue, 252 | int abright) { // SET ALL LEDS TO ONE COLOR (HSV) 253 | for (int i = 0; i < settings.num_leds; i++) { 254 | leds[i] = CHSV(ahue, 255, abright); 255 | } 256 | } 257 | 258 | int wrap(int step) { 259 | if (step < 0) return settings.num_leds + step; 260 | if (step > settings.num_leds - 1) return step - settings.num_leds; 261 | return step; 262 | } 263 | 264 | void ripple() { 265 | if (currentBg == nextBg) { 266 | nextBg = random(256); 267 | } else if (nextBg > currentBg) { 268 | currentBg++; 269 | } else { 270 | currentBg--; 271 | } 272 | for (uint16_t l = 0; l < settings.num_leds; l++) { 273 | leds[l] = CHSV(currentBg, 255, 274 | settings.effect_brightness); // strip.setPixelColor(l, 275 | // Wheel(currentBg, 0.1)); 276 | } 277 | 278 | if (step == -1) { 279 | center = random(settings.num_leds); 280 | color = random(256); 281 | step = 0; 282 | } 283 | 284 | if (step == 0) { 285 | leds[center] = CHSV( 286 | color, 255, settings.effect_brightness); // strip.setPixelColor(center, 287 | // Wheel(color, 1)); 288 | step++; 289 | } else { 290 | if (step < maxSteps) { 291 | //Serial.println(pow(fadeRate, step)); 292 | 293 | leds[wrap(center + step)] = 294 | CHSV(color, 255, 295 | pow(fadeRate, step) * 255); // strip.setPixelColor(wrap(center 296 | // + step), Wheel(color, 297 | // pow(fadeRate, step))); 298 | leds[wrap(center - step)] = 299 | CHSV(color, 255, 300 | pow(fadeRate, step) * 255); // strip.setPixelColor(wrap(center 301 | // - step), Wheel(color, 302 | // pow(fadeRate, step))); 303 | if (step > 3) { 304 | leds[wrap(center + step - 3)] = 305 | CHSV(color, 255, pow(fadeRate, step - 2) * 306 | 255); // strip.setPixelColor(wrap(center + 307 | // step - 3), Wheel(color, 308 | // pow(fadeRate, step - 2))); 309 | leds[wrap(center - step + 3)] = 310 | CHSV(color, 255, pow(fadeRate, step - 2) * 311 | 255); // strip.setPixelColor(wrap(center - 312 | // step + 3), Wheel(color, 313 | // pow(fadeRate, step - 2))); 314 | } 315 | step++; 316 | } else { 317 | step = -1; 318 | } 319 | } 320 | // if (settings.glitter_on == true){addGlitter(settings.glitter_density);} 321 | 322 | // frame has been created, now show it 323 | // FastLED.show(); 324 | // insert a delay to keep the framerate modest 325 | // FastLED.delay(int(float(1000/settings.fps))); 326 | } 327 | 328 | //***************************END LED 329 | //RIPPLE***************************************************** 330 | 331 | void comet() { 332 | fadeToBlackBy(leds, settings.num_leds, settings.ftb_speed); 333 | lead_dot = beatsin16(int(float(settings.fps / 3)), 0, settings.num_leds); 334 | leds[lead_dot] = CHSV(dothue, 200, 255); 335 | dothue += 8; 336 | // if (settings.glitter_on == true){addGlitter(settings.glitter_density);} 337 | // FastLED.show(); 338 | } 339 | 340 | // Theatre-style crawling lights. 341 | void theaterChase() { 342 | static int8_t frame = 0; 343 | 344 | // turn off the previous frame's led 345 | for (int i = 0; i < settings.num_leds; i = i + 3) { 346 | if (i + frame < settings.num_leds) { 347 | leds[i + frame] = CRGB(0, 0, 0); // turn every third pixel off 348 | } 349 | } 350 | 351 | // advance the frame 352 | frame++; 353 | if (frame > 2) frame = 0; 354 | 355 | // turn on the current frame's leds 356 | for (int i = 0; i < settings.num_leds; i = i + 3) { 357 | if (i + frame < settings.num_leds) { 358 | leds[i + frame] = 359 | CRGB(settings.main_color.red, settings.main_color.green, 360 | settings.main_color.blue); // turn every third pixel on 361 | } 362 | } 363 | } 364 | 365 | 366 | //***********TV 367 | int dipInterval = 10; 368 | int darkTime = 250; 369 | unsigned long currentDipTime; 370 | unsigned long dipStartTime; 371 | unsigned long currentMillis; 372 | int ledState = LOW; 373 | long previousMillis = 0; 374 | int ledBrightness[NUM_LEDS]; 375 | uint16_t ledHue[NUM_LEDS]; 376 | int led = 5; 377 | int interval = 2000; 378 | int twitch = 50; 379 | int dipCount = 0; 380 | int analogLevel = 100; 381 | boolean timeToDip = false; 382 | 383 | CRGB hsb2rgbAN1(uint16_t index, uint8_t sat, uint8_t bright) { 384 | // Source: https://blog.adafruit.com/2012/03/14/constant-brightness-hsb-to-rgb-algorithm/ 385 | uint8_t temp[5], n = (index >> 8) % 3; 386 | temp[0] = temp[3] = (uint8_t)(( (sat ^ 255) * bright) / 255); 387 | temp[1] = temp[4] = (uint8_t)((((( (index & 255) * sat) / 255) + (sat ^ 255)) * bright) / 255); 388 | temp[2] = (uint8_t)(((((((index & 255) ^ 255) * sat) / 255) + (sat ^ 255)) * bright) / 255); 389 | 390 | return CRGB(temp[n + 2], temp[n + 1], temp[n]); 391 | } 392 | 393 | void _tvUpdateLed (int led, int brightness) { 394 | ledBrightness[led] = brightness; 395 | for (int i=0; i interval) { 406 | previousMillis = currentMillis; 407 | interval = random(750,4001);//Adjusts the interval for more/less frequent random light changes 408 | twitch = random(40,100);// Twitch provides motion effect but can be a bit much if too high 409 | dipCount++; 410 | } 411 | if (currentMillis-previousMillis dipInterval) { 420 | //DBG_OUTPUT_PORT.println("dip"); 421 | timeToDip = true; 422 | dipCount = 0; 423 | dipStartTime = millis(); 424 | darkTime = random(50,150); 425 | dipInterval = random(5,250);// cycles of flicker 426 | } 427 | } 428 | } else { 429 | //DBG_OUTPUT_PORT.println("Dip Time"); 430 | currentDipTime = millis(); 431 | if (currentDipTime - dipStartTime < darkTime) { 432 | for (int i=3; i> 8) % 3, 200, ledBrightness[i]); 452 | 453 | leds[i] = hsb2rgbAN1(ledHue[i], sat, ledBrightness[i]).nscale8_video(flicker); 454 | } 455 | } 456 | 457 | // Fire2012 by Mark Kriegsman, July 2012 458 | // as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY 459 | //// 460 | // This basic one-dimensional 'fire' simulation works roughly as follows: 461 | // There's a underlying array of 'heat' cells, that model the temperature 462 | // at each point along the line. Every cycle through the simulation, 463 | // four steps are performed: 464 | // 1) All cells cool down a little bit, losing heat to the air 465 | // 2) The heat from each cell drifts 'up' and diffuses a little 466 | // 3) Sometimes randomly new 'sparks' of heat are added at the bottom 467 | // 4) The heat from each cell is rendered as a color into the leds array 468 | // The heat-to-color mapping uses a black-body radiation approximation. 469 | // 470 | // Temperature is in arbitrary units from 0 (cold black) to 255 (white hot). 471 | // 472 | // This simulation scales it self a bit depending on settings.num_leds; it should look 473 | // "OK" on anywhere from 20 to 100 LEDs without too much tweaking. 474 | // 475 | // I recommend running this simulation at anywhere from 30-100 frames per second, 476 | // meaning an interframe delay of about 10-35 milliseconds. 477 | // 478 | // Looks best on a high-density LED setup (60+ pixels/meter). 479 | // 480 | // 481 | // There are two main parameters you can play with to control the look and 482 | // feel of your fire: COOLING (used in step 1 above), and SPARKING (used 483 | // in step 3 above). 484 | // 485 | // COOLING: How much does the air cool as it rises? 486 | // Less cooling = taller flames. More cooling = shorter flames. 487 | // Default 55, suggested range 20-100 488 | #define COOLING 80 489 | 490 | // SPARKING: What chance (out of 255) is there that a new spark will be lit? 491 | // Higher chance = more roaring fire. Lower chance = more flickery fire. 492 | // Default 120, suggested range 50-200. 493 | #define SPARKING 60 494 | 495 | bool gReverseDirection = false; 496 | 497 | boolean _firerainbow = false; // used for rainbow mode 498 | 499 | 500 | void fire2012() 501 | { 502 | 503 | // Array of temperature readings at each simulation cell 504 | static byte heat[NUM_LEDS]; 505 | static byte heat2[NUM_LEDS]; 506 | 507 | // Step 1. Cool down every cell a little 508 | for( int i = 0; i < settings.num_leds; i++) { 509 | //heat[i] = qsub8( heat[i], random8(0, ((COOLING * 10) / settings.num_leds) + 2)); // original with COOLING 510 | heat[i] = qsub8( heat[i], random8(0, ((settings.ftb_speed * 20) / settings.num_leds) + 2)); // modified with FTBspeed 511 | heat2[i] = qsub8( heat2[i], random8(0, ((settings.ftb_speed * 20) / settings.num_leds) + 2)); // modified with FTBspeed 512 | } 513 | 514 | // Step 2. Heat from each cell drifts 'up' and diffuses a little 515 | for( int k= settings.num_leds - 1; k >= 2; k--) { 516 | 517 | heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3; 518 | heat2[k] = (heat2[k - 1] + heat2[k - 2] + heat2[k - 2] ) / 3; 519 | 520 | } 521 | 522 | // Step 3. Randomly ignite new 'sparks' of heat near the bottom 523 | // if( random8() < SPARKING ) { // Original with SPARKING 524 | if( random8() < settings.show_length ) { // Modified with show_length 525 | int y = random8(7); 526 | int z = random8(7); 527 | heat[y] = qadd8( heat[y], random8(160,255) ); 528 | heat2[z] = qadd8( heat2[z], random8(160,255) ); 529 | } 530 | 531 | // Step 4. Map from heat cells to LED colors 532 | for( int j = 0; j < (settings.num_leds / 2); j++) { 533 | CRGB color = HeatColor( heat[j]); 534 | int pixelnumber; 535 | if( gReverseDirection ) { 536 | pixelnumber = (settings.num_leds-1) - j; 537 | } else { 538 | pixelnumber = j; 539 | } 540 | leds[pixelnumber] = color; 541 | } 542 | 543 | // Step 4. Map from heat cells to LED colors 544 | for( int j = 0; j < (settings.num_leds / 2); j++) { 545 | CRGB color = HeatColor( heat2[j]); 546 | int pixelnumber; 547 | pixelnumber = (settings.num_leds-1) - j; 548 | leds[pixelnumber] = color; 549 | } 550 | 551 | if (_firerainbow) { 552 | for( int j = 0; j < (settings.num_leds); j++) { 553 | leds[j] += CHSV(gHue, 255, settings.effect_brightness); // set effect brightness 554 | } 555 | _firerainbow = false; 556 | } 557 | 558 | ////frame has been created, now show it 559 | // FastLED.show(); 560 | // // insert a delay to keep the framerate modest 561 | // FastLED.delay(int(float(1000/FPS))); 562 | 563 | } 564 | 565 | void fire_rainbow() { 566 | _firerainbow = true; 567 | fire2012(); 568 | 569 | } 570 | 571 | 572 | // Fireworks from WS2812FX 573 | 574 | boolean _singlecolor = false; // used for single color mode 575 | boolean _rainbow = false; // used for rainbow mode 576 | 577 | void fireworks() { 578 | 579 | 580 | 581 | // fadeToBlackBy( leds, settings.num_leds, ftb_speed); 582 | 583 | 584 | uint32_t px_rgb = 0; 585 | byte px_r = 0; 586 | byte px_g = 0; 587 | byte px_b = 0; 588 | byte px_boost = 200; 589 | 590 | for(uint16_t i=0; i < settings.num_leds; i++) { 591 | 592 | 593 | 594 | //leds[i] /= 2; // fade out (divide by 2) 595 | leds[i].nscale8(130 - int(float(settings.ftb_speed*0.5))); 596 | //leds[i].fadeToBlackBy(ftb_speed); 597 | 598 | } 599 | 600 | // first LED has only one neighbour 601 | leds[0].r = (leds[1].r >> 1) + leds[0].r; 602 | leds[0].g = (leds[1].g >> 1) + leds[0].g; 603 | leds[0].b = (leds[1].b >> 1) + leds[0].b; 604 | //leds[0].setRGB(px_r, px_g, px_b); 605 | 606 | // set brightness(i) = ((brightness(i-1)/2 + brightness(i+1)) / 2) + brightness(i) 607 | for(uint16_t i=1; i < settings.num_leds-1; i++) { 608 | leds[i].r = (( 609 | (leds[i-1].r >> 1) + 610 | leds[i+1].r ) >> 1) + 611 | leds[i].r; 612 | 613 | leds[i].g = (( 614 | (leds[i-1].g >> 1) + 615 | leds[i+1].g ) >> 1) + 616 | leds[i].g; 617 | 618 | leds[i].b = (( 619 | (leds[i-1].b >> 1) + 620 | leds[i+1].b ) >> 1) + 621 | leds[i].b; 622 | } 623 | 624 | // last LED has only one neighbour 625 | leds[settings.num_leds-1].r = ((leds[settings.num_leds-2].r >> 2) + leds[settings.num_leds-1].r); 626 | leds[settings.num_leds-1].g = ((leds[settings.num_leds-2].g >> 2) + leds[settings.num_leds-1].g); 627 | leds[settings.num_leds-1].b = ((leds[settings.num_leds-2].b >> 2) + leds[settings.num_leds-1].b); 628 | 629 | px_r = random8(); 630 | px_g = random8(); 631 | px_b = random8(); 632 | 633 | 634 | 635 | for(uint16_t i=0; i<_max(1,settings.num_leds/20); i++) { 636 | if(random8(settings.show_length + 4) == 0) { 637 | //Adafruit_NeoPixel::setPixelColor(random(_led_count), _mode_color); 638 | byte pixel = random(settings.num_leds); 639 | if(_singlecolor){ 640 | leds[pixel] = CRGB(settings.main_color.red,settings.main_color.green,settings.main_color.blue); // tails are in single color from set color on web interface 641 | } else if(_rainbow) { 642 | leds[pixel] = CHSV( gHue, 255, settings.effect_brightness); // Rainbow cycling color 643 | } else if(!_singlecolor && !_rainbow) { 644 | leds[pixel].setRGB(px_r, px_g, px_b); // Multicolored tale 645 | 646 | } 647 | leds[pixel].maximizeBrightness(); 648 | 649 | 650 | 651 | } 652 | } 653 | 654 | _singlecolor = false; 655 | _rainbow = false; 656 | 657 | // if (GLITTER_ON == true){addGlitter(glitter_density);} 658 | // //frame has been created, now show it 659 | FastLED.show(); 660 | // insert a delay to keep the framerate modest 661 | // FastLED.delay(int(float(1000/FPS))); 662 | } 663 | 664 | 665 | 666 | void fw_single() { 667 | _singlecolor = true; 668 | fireworks(); 669 | } 670 | 671 | void fw_rainbow() { 672 | _rainbow = true; 673 | fireworks(); 674 | } 675 | 676 | // END 677 | 678 | 679 | //*******************************ARRAY OF SHOW ANIMATIONS FOR MIXED SHOW 680 | //MODE*********************** 681 | typedef void (*SimplePatternList[])(); 682 | SimplePatternList gPatterns = {rainbow, confetti, sinelon, juggle, 683 | bpm, palette_anims, ripple, comet}; 684 | //************************************************************************************************** 685 | -------------------------------------------------------------------------------- /data-moved_aside/color-selector.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Getting colors 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 130 | 131 |
132 | 133 |
134 | toHEXString =
135 | toRGBString =
136 | R, G, B =
137 | H, S, V = 138 |
139 | 140 | 141 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /data-moved_aside/graphs.htm: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | ESP Monitor 23 | 24 | 85 | 86 | 87 |
88 | 89 | 90 | 91 | 92 |
93 |
94 |
95 |
96 | 97 | -------------------------------------------------------------------------------- /data-moved_aside/graphs.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data-moved_aside/graphs.js.gz -------------------------------------------------------------------------------- /data/custom.css: -------------------------------------------------------------------------------- 1 | .isactive { 2 | color: #fa3; 3 | } 4 | 5 | .switch label input[type=checkbox]:checked+.lever { 6 | background-color: #fa3; 7 | } 8 | 9 | .switch label input[type=checkbox]:checked+.lever:after { 10 | background-color: #f93; 11 | } 12 | 13 | .noUI-connect { 14 | background: #f93 ; 15 | } 16 | 17 | .range-label{ 18 | background-color: #f93; 19 | } 20 | 21 | .noUI-background { 22 | background: #f93; 23 | } 24 | 25 | input[type=range]::-webkit-slider-thumb { 26 | background-color: #455a64; 27 | } 28 | input[type=range]::-moz-range-thumb { 29 | background-color: #455a64; 30 | } 31 | input[type=range]::-ms-thumb { 32 | background-color: #455a64; 33 | } 34 | 35 | /***** These are to edit the thumb and the text inside the thumb *****/ 36 | input[type=range] + .thumb { 37 | background-color: #455a64; 38 | } 39 | input[type=range] + .thumb.active .value { 40 | color: white; 41 | } -------------------------------------------------------------------------------- /data/edit.htm.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/edit.htm.gz -------------------------------------------------------------------------------- /data/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/favicon.ico -------------------------------------------------------------------------------- /data/index.htm.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/index.htm.gz -------------------------------------------------------------------------------- /data/jscolor.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/jscolor.js.gz -------------------------------------------------------------------------------- /data/offline.appcache: -------------------------------------------------------------------------------- 1 | CACHE MANIFEST 2 | 3 | # Explicitly cached 'master entries'. 4 | # index.html 5 | http://code.jquery.com/jquery-3.2.1.min.js 6 | http://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js 7 | http://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.min.css 8 | http://fonts.googleapis.com/icon?family=Material+Icons 9 | 10 | 11 | # Resources that require the user to be online. 12 | NETWORK: 13 | * -------------------------------------------------------------------------------- /data/palettes/35_blue_waves.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/35_blue_waves.bin -------------------------------------------------------------------------------- /data/palettes/37_waves.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/37_waves.bin -------------------------------------------------------------------------------- /data/palettes/Green_White_Red.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/Green_White_Red.bin -------------------------------------------------------------------------------- /data/palettes/Lindaa07.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/Lindaa07.bin -------------------------------------------------------------------------------- /data/palettes/beading.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/beading.bin -------------------------------------------------------------------------------- /data/palettes/bhw1_29.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/bhw1_29.bin -------------------------------------------------------------------------------- /data/palettes/bhw1_greenie.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/bhw1_greenie.bin -------------------------------------------------------------------------------- /data/palettes/bhw1_purpgreen.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/bhw1_purpgreen.bin -------------------------------------------------------------------------------- /data/palettes/bhw1_purplered.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/bhw1_purplered.bin -------------------------------------------------------------------------------- /data/palettes/bhw1_sunconure.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/bhw1_sunconure.bin -------------------------------------------------------------------------------- /data/palettes/bhw2_xmas.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/bhw2_xmas.bin -------------------------------------------------------------------------------- /data/palettes/blueeyedgal.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/blueeyedgal.bin -------------------------------------------------------------------------------- /data/palettes/brightsong2.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/brightsong2.bin -------------------------------------------------------------------------------- /data/palettes/bud2.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/bud2.bin -------------------------------------------------------------------------------- /data/palettes/christmas-candy.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/christmas-candy.bin -------------------------------------------------------------------------------- /data/palettes/faewing3.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/faewing3.bin -------------------------------------------------------------------------------- /data/palettes/goddess-moon.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/goddess-moon.bin -------------------------------------------------------------------------------- /data/palettes/lkmtch00.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/lkmtch00.bin -------------------------------------------------------------------------------- /data/palettes/patriot.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/patriot.bin -------------------------------------------------------------------------------- /data/palettes/plasma.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/plasma.bin -------------------------------------------------------------------------------- /data/palettes/prism.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/prism.bin -------------------------------------------------------------------------------- /data/palettes/sls.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/sls.bin -------------------------------------------------------------------------------- /data/palettes/sorcery-2.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/sorcery-2.bin -------------------------------------------------------------------------------- /data/palettes/starrynite.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/starrynite.bin -------------------------------------------------------------------------------- /data/palettes/twilight.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/twilight.bin -------------------------------------------------------------------------------- /data/palettes/usa1.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/usa1.bin -------------------------------------------------------------------------------- /data/palettes/water1.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/water1.bin -------------------------------------------------------------------------------- /data/palettes/wintercolors.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/data/palettes/wintercolors.bin -------------------------------------------------------------------------------- /definitions.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 @jake-b, @russp81, @toblum 2 | // Griswold LED Lighting Controller 3 | 4 | // Griswold is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of 7 | // the License, or (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU Lesser General Public License 15 | // along with this program. If not, see . 16 | 17 | // Griswold is a fork of the LEDLAMP project at 18 | // https://github.com/russp81/LEDLAMP_FASTLEDs 19 | 20 | // The LEDLAMP project is a fork of the McLighting Project at 21 | // https://github.com/toblum/McLighting 22 | 23 | #define FASTLED_ALLOW_INTERRUPTS 0 24 | 25 | /// Serial 26 | #define DEBUG_WEBSOCKETS(...) Serial.printf( __VA_ARGS__ ) 27 | 28 | 29 | #define FASTLED_USE_PROGMEM 1 30 | // Note, you need to patch FastLEDs in order to use this. You'll get an 31 | // error related to . Saves more than 3k given the palettes 32 | // 33 | // Simply edit and update the include (Line ~29): 34 | // #if FASTLED_INCLUDE_PGMSPACE == 1 35 | // #if (defined(__AVR__)) 36 | // #include 37 | // #else 38 | // #include 39 | // #endif 40 | // #endif 41 | 42 | #define FASTLED_INTERRUPT_RETRY_COUNT 3 43 | #include "FastLED.h" 44 | #if defined(FASTLED_VERSION) && (FASTLED_VERSION < 3001000) 45 | #warning "Requires FastLED 3.1 or later; check github for latest code." 46 | #endif 47 | 48 | #define HOSTNAME_PREFIX "LEDCONTROL" 49 | 50 | //#define REMOTE_DEBUG 51 | 52 | #define DATA_PIN 2 53 | //#define CLK_PIN 4 54 | #define LED_TYPE WS2812B 55 | #define COLOR_ORDER GRB 56 | #define NUM_LEDS 1000 // dummy for initial setup the fastled routines 57 | // #define MAX_CURRENT 1800 // limit to max current 58 | #define FASTLED_HZ 100 // maximum FASTLED refresh rate ( default = 400) 59 | CRGB leds[NUM_LEDS]; 60 | 61 | #define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0])) 62 | 63 | enum MODE { HOLD, 64 | OFF, 65 | ALL, 66 | MIXEDSHOW, 67 | RAINBOW, 68 | CONFETTI, 69 | SINELON, 70 | JUGGLE, 71 | BPM, 72 | PALETTE_ANIMS, 73 | RIPPLE, 74 | COMET, 75 | THEATERCHASE, 76 | WIPE, 77 | TV, 78 | FIRE, 79 | FIRE_RAINBOW, 80 | FIREWORKS, 81 | FIREWORKS_SINGLE, 82 | FIREWORKS_RAINBOW,}; 83 | 84 | enum DIRECTION { 85 | BACK = 0, 86 | FORWARD = 1, }; 87 | 88 | // These globals moved to the settings struct 89 | //MODE mode = OFF; // Standard mode that is active when software starts 90 | //uint8_t FPS = 50; // Global variable for storing the frames per second 91 | //uint8_t brightness = 255; // Global variable for storing the brightness (255 == 100%) 92 | //uint8_t show_length = 15; // Global variable for storing the show_time (in seconds) 93 | //uint8_t ftb_speed = 50; // Global variable for fade to black speed 94 | //uint8_t glitter_density = 50; // Global variable for glitter density 95 | long lastMillis = 0; // Global variable for timechecking last show cycle time 96 | long theaterMillis = 0; 97 | long paletteMillis = 0; // Global variable for timechecking color palette shifts 98 | //bool exit_func = false; // Global helper variable to get out of the color modes when mode changes 99 | //bool GLITTER_ON = false; // Global to add / remove glitter to any animation 100 | 101 | //******Palette Animation Globals******************************************* 102 | uint8_t targetPaletteIndex; 103 | uint8_t currentPaletteIndex; 104 | uint8_t colorIndex; 105 | DIRECTION anim_direction = FORWARD; 106 | CRGBPalette16 currentPalette; 107 | CRGBPalette16 targetPalette; 108 | TBlendType currentBlending; 109 | 110 | //*************************************************************************** 111 | 112 | //***************RIPPLE****************************************************** 113 | int color; 114 | int center = 0; 115 | int step = -1; 116 | int maxSteps = 32; 117 | float fadeRate = 0.8; 118 | int diff; 119 | 120 | //background color 121 | uint32_t currentBg = random(256); 122 | uint32_t nextBg = currentBg; 123 | //****************************************************************************** 124 | 125 | byte dothue = 0; 126 | int lead_dot = 0; 127 | 128 | uint8_t gCurrentPatternNumber = 0; // Index number of which pattern is current 129 | uint8_t gHue = 0; // rotating "base color" used by many of the patterns 130 | 131 | struct ledstate // Data structure to store a state of a single led 132 | { 133 | uint8_t red; 134 | uint8_t green; 135 | uint8_t blue; 136 | }; 137 | 138 | typedef struct ledstate LEDState; // Define the datatype LEDState 139 | LEDState ledstates[NUM_LEDS]; // Get an array of led states to store the state of the whole strip 140 | //LEDState main_color; // Store the "main color" of the strip used in single color modes 141 | //LEDState glitter_color; // Store the "glitter color" of the strip for glitter mode 142 | 143 | // Supporting the "Glitter Wipe" effect 144 | #define SPARKLE_SPREAD (_max(settings.num_leds/80,3)) 145 | #define WIPE_SPEED (_max(settings.num_leds/120,1)) 146 | int16_t wipePos = 0; 147 | 148 | #ifdef REMOTE_DEBUG 149 | RemoteDebug Debug; 150 | #define DBG_OUTPUT_PORT Debug 151 | #else 152 | #define DBG_OUTPUT_PORT Serial 153 | #endif 154 | -------------------------------------------------------------------------------- /documentation/large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/documentation/large.png -------------------------------------------------------------------------------- /documentation/large50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/documentation/large50.png -------------------------------------------------------------------------------- /documentation/small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/documentation/small.png -------------------------------------------------------------------------------- /documentation/small50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/documentation/small50.png -------------------------------------------------------------------------------- /eepromsettings.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 @jake-b, @russp81, @toblum 2 | // Griswold LED Lighting Controller 3 | 4 | // Griswold is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of 7 | // the License, or (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU Lesser General Public License 15 | // along with this program. If not, see . 16 | 17 | // Griswold is a fork of the LEDLAMP project at 18 | // https://github.com/russp81/LEDLAMP_FASTLEDs 19 | 20 | // The LEDLAMP project is a fork of the McLighting Project at 21 | // https://github.com/toblum/McLighting 22 | 23 | #include 24 | 25 | // EEPROM stuff 26 | // adapted from https://github.com/esp8266/Arduino/issues/1090 27 | 28 | #pragma pack(push) // push current alignment to stack 29 | #pragma pack(1) // set alignment to 1 byte boundary 30 | typedef struct { 31 | MODE mode; 32 | uint8_t fps = 50; // Global variable for storing the frames per second 33 | uint8_t overall_brightness = 255; // Global variable for storing the brightness (255 == 100%) 34 | uint8_t show_length = 15; // Global variable for storing the show_time (in seconds) 35 | uint8_t ftb_speed = 50; // Global variable for fade to black speed 36 | uint8_t glitter_density = 50; // Global variable for glitter density 37 | bool glitter_on = false; // Global to add / remove glitter to any animation 38 | LEDState main_color; // Store the "main color" of the strip used in single 39 | // color modes 40 | LEDState glitter_color; // Store the "glitter color" of the strip for glitter mode 41 | uint8_t effect_brightness = 255; // Brightness used for effect animations 42 | int8_t palette_ndx = -1; // Palette to use for PALETTE_ANIMS. -1 is change periodically 43 | uint8_t confetti_dens = 1; // Density for the confetti effect. More confetti needed for longer strings. 44 | bool glitter_wipe_on = false; 45 | uint16_t num_leds = 50; // number of connected leds 46 | uint16_t max_current = 1800; // maximum allowed current in milliamperes 47 | uint8_t filler[46]; // in case adding data in config avoiding loosing current conf by bad crc 48 | uint16_t crc; 49 | } EEPROMSettings; 50 | #pragma pack(pop) 51 | 52 | EEPROMSettings settings; 53 | 54 | uint16_t crc16Update(uint16_t crc, uint8_t a) { 55 | int i; 56 | crc ^= a; 57 | for (i = 0; i < 8; ++i) { 58 | if (crc & 1) 59 | crc = (crc >> 1) ^ 0xA001; 60 | else 61 | crc = (crc >> 1); 62 | } 63 | return crc; 64 | } 65 | 66 | void loadDefaults() { 67 | settings.mode = OFF; 68 | settings.fps = 50; // Global variable for storing the frames per second 69 | settings.overall_brightness = 255; // Global variable for storing the brightness (255 == 100%) 70 | settings.effect_brightness = 128; // Global variable for storing the palette brightness (255 == 100%) 71 | settings.show_length = 15; // Global variable for storing the show_time (in seconds) 72 | settings.ftb_speed = 50; // Global variable for fade to black speed 73 | settings.glitter_density = 50; // Global variable for glitter density 74 | settings.glitter_on = false; // Global to add / remove glitter to any animation 75 | settings.main_color = { 128, 128, 128}; // Store the "main color" of the strip used in single color modes 76 | settings.glitter_color = {128, 128, 128}; 77 | settings.palette_ndx = -1; 78 | settings.confetti_dens = 1; 79 | settings.glitter_wipe_on = false; 80 | settings.num_leds = 50; 81 | settings.max_current = 1800; 82 | } 83 | 84 | bool readSettings(bool clear_on_error) { 85 | uint16_t crc = ~0; 86 | uint8_t* pconfig = (uint8_t*)&settings; 87 | uint8_t data; 88 | 89 | // For whole size of config structure 90 | for (uint16_t i = 0; i < sizeof(EEPROMSettings); ++i) { 91 | // read data 92 | data = EEPROM.read(i); 93 | 94 | // save into struct 95 | *pconfig++ = data; 96 | 97 | // calc CRC 98 | crc = crc16Update(crc, data); 99 | } 100 | 101 | // CRC Error ? 102 | if (crc != 0) { 103 | DBG_OUTPUT_PORT.println("Settings CRC failed on read from EEPROM"); 104 | // Clear config if wanted 105 | if (clear_on_error) { 106 | memset(&settings, 0, sizeof(EEPROMSettings)); 107 | 108 | // Set defaults 109 | loadDefaults(); 110 | return false; 111 | } 112 | } 113 | 114 | DBG_OUTPUT_PORT.println("Settings successfully read from EERPOM"); 115 | return true; 116 | } 117 | 118 | bool saveSettings(void) { 119 | uint8_t* pconfig; 120 | bool ret_code; 121 | 122 | // Init pointer 123 | pconfig = (uint8_t*)&settings; 124 | 125 | // Init CRC 126 | settings.crc = ~0; 127 | 128 | // For whole size of config structure, pre-calculate CRC 129 | for (uint16_t i = 0; i < sizeof(EEPROMSettings) - 2; ++i) 130 | settings.crc = crc16Update(settings.crc, *pconfig++); 131 | 132 | // Re init pointer 133 | pconfig = (uint8_t*)&settings; 134 | 135 | // For whole size of config structure, write to EEP 136 | for (uint16_t i = 0; i < sizeof(EEPROMSettings); ++i) 137 | EEPROM.write(i, *pconfig++); 138 | 139 | // Physically save 140 | EEPROM.commit(); 141 | 142 | // Read Again to see if saved ok, but do 143 | // not clear if error this avoid clearing 144 | // default config and breaks OTA 145 | ret_code = readSettings(false); 146 | 147 | DBG_OUTPUT_PORT.print("Write settings to EEPROM: "); 148 | 149 | if (ret_code) 150 | DBG_OUTPUT_PORT.println(F("OK!")); 151 | else 152 | DBG_OUTPUT_PORT.println(F("Error!")); 153 | 154 | // return result 155 | return (ret_code); 156 | } 157 | 158 | void printSettings() { 159 | DBG_OUTPUT_PORT.println("Current settings in RAM:"); 160 | 161 | DBG_OUTPUT_PORT.printf("mode: %d\n", 162 | settings.mode); 163 | DBG_OUTPUT_PORT.printf("fps: %d\n", 164 | settings.fps); // Global variable for storing the frames per second 165 | DBG_OUTPUT_PORT.printf("overall_brightness: %d\n", 166 | settings.overall_brightness); // Global variable for storing the brightness (255 == 100%) 167 | DBG_OUTPUT_PORT.printf("effect_brightness: %d\n", 168 | settings.effect_brightness); // Global variable for storing the brightnes (255 == 100%) 169 | DBG_OUTPUT_PORT.printf("show_length: %d\n", 170 | settings.show_length); // Global variable for storing 171 | // the show_time (in seconds) 172 | DBG_OUTPUT_PORT.printf("ftb_speed: %d\n", 173 | settings.ftb_speed); // Global variable for fade to black speed 174 | DBG_OUTPUT_PORT.printf("glitter_density: %d\n", 175 | settings.glitter_density); // Global variable for glitter density 176 | DBG_OUTPUT_PORT.printf("glitter_on: %d\n", 177 | settings.glitter_on); // Global to add / remove glitter to any animation 178 | DBG_OUTPUT_PORT.printf("main_color: %d,%d,%d\n", 179 | settings.main_color.red, settings.main_color.green, 180 | settings.main_color.blue); // Store the "main color" of the strip used in single color modes 181 | DBG_OUTPUT_PORT.printf("glitter_color: %d,%d,%d\n", settings.glitter_color.red, 182 | settings.glitter_color.green, settings.glitter_color.blue); 183 | DBG_OUTPUT_PORT.printf("palette_ndx: %d\n", settings.palette_ndx); // selected palette 184 | DBG_OUTPUT_PORT.printf("confetti_dens: %d\n", settings.confetti_dens); // selected palette 185 | DBG_OUTPUT_PORT.printf("numleds: %d\n", 186 | settings.num_leds); // Global variable for number of leds 187 | DBG_OUTPUT_PORT.printf("maxcurrent: %d\n", 188 | settings.max_current); // Global variable for glitter density 189 | } 190 | 191 | void initSettings() { 192 | EEPROM.begin(sizeof(EEPROMSettings)); 193 | if (readSettings(true)) { 194 | DBG_OUTPUT_PORT.println("Successfully read settings from EEPROM"); 195 | } else { 196 | DBG_OUTPUT_PORT.println( 197 | "Failed read settings from EEPROM, defaults loaded."); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /palette_convert/alpen.txt: -------------------------------------------------------------------------------- 1 | /* 2 | CSS3 gradient 3 | cptutils 1.46 4 | Wed Aug 15 23:30:37 2012 5 | */ 6 | 7 | linear-gradient( 8 | 0deg, 9 | rgb( 14, 8, 12) 0.000%, 10 | rgb( 14, 8, 12) 88.000%, 11 | rgb(216, 84, 71) 88.000%, 12 | rgb(216, 84, 71) 91.000%, 13 | rgb(253,146, 91) 91.000%, 14 | rgb(253,146, 91) 94.000%, 15 | rgb(248,203,118) 94.000%, 16 | rgb(248,203,118) 97.000%, 17 | rgb(147,191, 90) 97.000%, 18 | rgb(147,191, 90) 100.000% 19 | ); -------------------------------------------------------------------------------- /palette_convert/alpen_mango.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/palette_convert/alpen_mango.bin -------------------------------------------------------------------------------- /palette_convert/alpen_natural.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/palette_convert/alpen_natural.bin -------------------------------------------------------------------------------- /palette_convert/alpen_refuel.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/palette_convert/alpen_refuel.bin -------------------------------------------------------------------------------- /palette_convert/bhw1_greenie.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/palette_convert/bhw1_greenie.bin -------------------------------------------------------------------------------- /palette_convert/bhw2_23.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/palette_convert/bhw2_23.bin -------------------------------------------------------------------------------- /palette_convert/colo_starcrossed.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/palette_convert/colo_starcrossed.bin -------------------------------------------------------------------------------- /palette_convert/colo_tastetherain.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/palette_convert/colo_tastetherain.bin -------------------------------------------------------------------------------- /palette_convert/ggr_blinds.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/palette_convert/ggr_blinds.bin -------------------------------------------------------------------------------- /palette_convert/ggr_fourbars.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/palette_convert/ggr_fourbars.bin -------------------------------------------------------------------------------- /palette_convert/imagej_edges.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/palette_convert/imagej_edges.bin -------------------------------------------------------------------------------- /palette_convert/palette_convert.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | 3 | # Griswold is a fork of the LEDLAMP project at 4 | # https://github.com/russp81/LEDLAMP_FASTLEDs 5 | 6 | # The LEDLAMP project is a fork of the McLighting Project at 7 | # https://github.com/toblum/McLighting 8 | 9 | # PaletteKnife was released under the MIT License (MIT), and hence this is as well. 10 | 11 | # Copyright (c) 2016 @jake-b 12 | 13 | # Permission is hereby granted, free of charge, to any person obtaining a copy of 14 | # this software and associated documentation files (the "Software"), to deal in 15 | # the Software without restriction, including without limitation the rights to 16 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 17 | # the Software, and to permit persons to whom the Software is furnished to do so, 18 | # subject to the following conditions: 19 | 20 | # The above copyright notice and this permission notice shall be included in all 21 | # copies or substantial portions of the Software. 22 | 23 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 25 | # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 26 | # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 27 | # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 28 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | 30 | # This is a rudamentary clone of PaletteKnife, designed to output the palette to a 31 | # file in binary format. 32 | 33 | import sys 34 | import re 35 | import math 36 | import os 37 | 38 | def adjustGamma(orig, gamma): 39 | o = orig / 255.0; 40 | adj = math.pow( o, gamma); 41 | res = math.floor( adj * 255.0); 42 | if ((orig != 0) and (res == 0)): 43 | res = 1; 44 | return int(res); 45 | 46 | 47 | infile = sys.argv[1] 48 | outfile = os.path.splitext(infile)[0] + ".bin" 49 | 50 | print "Processing file: " + infile 51 | 52 | with open(infile) as f: 53 | content = f.read() 54 | output_bytes = [] 55 | 56 | regex = re.compile('.*\(\s*([0-9]+), *([0-9]+), *([0-9]+)\)\s+([0-9.]+)') 57 | 58 | # RGBA Warning 59 | if content.find("rgba(") != -1: 60 | print("WARNING: TRANSPARENCY not supported."); 61 | 62 | count = 0 63 | for line in content.split('\n'): 64 | match = regex.match(line) 65 | 66 | if match: 67 | #print len(match) 68 | r = int(match.group(1)) 69 | g = int(match.group(2)) 70 | b = int(match.group(3)) 71 | pct = float(match.group(4)) 72 | ndx = int(math.floor( (pct * 255.0) / 100.0 )) 73 | 74 | output_bytes.append(ndx) 75 | output_bytes.append(adjustGamma(r, 2.6)) 76 | output_bytes.append(adjustGamma(g, 2.2)) 77 | output_bytes.append(adjustGamma(b, 2.5)) 78 | 79 | f.close() 80 | 81 | newFileByteArray = bytearray(output_bytes) 82 | with open(outfile,'wb') as newFile: 83 | newFile.write(newFileByteArray) 84 | newFile.close() 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /palette_convert/vredeling_sleep.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctormord/Responsive_LED_Control/18f61be0a325c35fa90150cbecc8023d7f6165d4/palette_convert/vredeling_sleep.bin -------------------------------------------------------------------------------- /palettes.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 @jake-b, @russp81, @toblum 2 | // Griswold LED Lighting Controller 3 | 4 | // Griswold is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of 7 | // the License, or (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU Lesser General Public License 15 | // along with this program. If not, see . 16 | 17 | // Griswold is a fork of the LEDLAMP project at 18 | // https://github.com/russp81/LEDLAMP_FASTLEDs 19 | 20 | // The LEDLAMP project is a fork of the McLighting Project at 21 | // https://github.com/toblum/McLighting 22 | 23 | int paletteCount = 0; 24 | 25 | int getPaletteCount() { 26 | Dir dir = SPIFFS.openDir("/palettes"); 27 | int palette_count = 0; 28 | while (dir.next()) { 29 | palette_count++; 30 | } 31 | DBG_OUTPUT_PORT.printf("Palette count: %d\n", palette_count); 32 | return palette_count; 33 | } 34 | 35 | bool openPaletteFileWithIndex(int index, File* file) { 36 | Dir dir = SPIFFS.openDir("/palettes"); 37 | 38 | int palette_count = 0; 39 | while (dir.next()) { 40 | if (palette_count == index) break; 41 | palette_count++; 42 | } 43 | 44 | if (palette_count != index) { 45 | DBG_OUTPUT_PORT.println("Error, unable to open palette"); 46 | return false; 47 | } 48 | 49 | *file = dir.openFile("r"); 50 | return true; //success 51 | } 52 | 53 | bool loadPaletteFromFile(int index, CRGBPalette16* palette) { 54 | File paletteFile; 55 | if (!openPaletteFileWithIndex(index, &paletteFile)) { 56 | DBG_OUTPUT_PORT.printf("Error loading paletteFile at index %d\n", index); 57 | return false; 58 | } 59 | 60 | int paletteFileSize = paletteFile.size(); 61 | uint8_t* bytes = new uint8_t[paletteFileSize]; 62 | if (!bytes) { 63 | DBG_OUTPUT_PORT.println("Unable to allocate memory for palette"); 64 | return false; 65 | } 66 | 67 | paletteFile.readBytes((char*)bytes, paletteFileSize); 68 | DBG_OUTPUT_PORT.printf("Load palette named %s (%d bytes)\n", paletteFile.name(), paletteFileSize); 69 | paletteFile.close(); 70 | 71 | 72 | palette->loadDynamicGradientPalette(bytes); 73 | 74 | delete[] bytes; 75 | return true; 76 | } 77 | 78 | 79 | String getPaletteNameWithIndex(int index) { 80 | Dir dir = SPIFFS.openDir("/palettes"); 81 | 82 | int ndx = 0; 83 | while (dir.next()) { 84 | if (ndx == index) return dir.fileName(); 85 | ndx++; 86 | } 87 | return "[unknown]"; 88 | } 89 | -------------------------------------------------------------------------------- /request_handlers.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 @jake-b, @russp81, @toblum 2 | // Griswold LED Lighting Controller 3 | 4 | // Griswold is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Lesser General Public License as 6 | // published by the Free Software Foundation, either version 3 of 7 | // the License, or (at your option) any later version. 8 | 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU Lesser General Public License 15 | // along with this program. If not, see . 16 | 17 | // Griswold is a fork of the LEDLAMP project at 18 | // https://github.com/russp81/LEDLAMP_FASTLEDs 19 | 20 | // The LEDLAMP project is a fork of the McLighting Project at 21 | // https://github.com/toblum/McLighting 22 | 23 | // *************************************************************************** 24 | // Request handlers 25 | // *************************************************************************** 26 | void getArgs() { 27 | if (server.arg("rgb") != "") { 28 | uint32_t rgb = (uint32_t) strtol(server.arg("rgb").c_str(), NULL, 16); 29 | settings.main_color.red = ((rgb >> 16) & 0xFF); 30 | settings.main_color.green = ((rgb >> 8) & 0xFF); 31 | settings.main_color.blue = ((rgb >> 0) & 0xFF); 32 | } else { 33 | settings.main_color.red = server.arg("r").toInt(); 34 | settings.main_color.green = server.arg("g").toInt(); 35 | settings.main_color.blue = server.arg("b").toInt(); 36 | } 37 | if (server.arg("d") != "") { 38 | settings.fps = server.arg("d").toInt(); 39 | if (settings.fps == 0) settings.fps = 40; // prevent divide by zero! 40 | } 41 | if (settings.main_color.red > 255) { 42 | settings.main_color.red = 255; 43 | } 44 | if (settings.main_color.green > 255) { 45 | settings.main_color.green = 255; 46 | } 47 | if (settings.main_color.blue > 255) { 48 | settings.main_color.blue = 255; 49 | } 50 | 51 | if (settings.main_color.red < 0) { 52 | settings.main_color.red = 0; 53 | } 54 | if (settings.main_color.green < 0) { 55 | settings.main_color.green = 0; 56 | } 57 | if (settings.main_color.blue < 0) { 58 | settings.main_color.blue = 0; 59 | } 60 | 61 | DBG_OUTPUT_PORT.print("Mode: "); 62 | DBG_OUTPUT_PORT.print(settings.mode); 63 | DBG_OUTPUT_PORT.print(", Color: "); 64 | DBG_OUTPUT_PORT.print(settings.main_color.red); 65 | DBG_OUTPUT_PORT.print(", "); 66 | DBG_OUTPUT_PORT.print(settings.main_color.green); 67 | DBG_OUTPUT_PORT.print(", "); 68 | DBG_OUTPUT_PORT.print(settings.main_color.blue); 69 | DBG_OUTPUT_PORT.print(", Delay:"); 70 | DBG_OUTPUT_PORT.print(settings.fps); 71 | DBG_OUTPUT_PORT.print(", Brightness:"); 72 | DBG_OUTPUT_PORT.println(settings.overall_brightness); 73 | DBG_OUTPUT_PORT.print(", show_length:"); 74 | DBG_OUTPUT_PORT.println(settings.show_length); 75 | } 76 | 77 | void handleMinimalUpload() { 78 | char temp[1500]; 79 | int sec = millis() / 1000; 80 | int min = sec / 60; 81 | int hr = min / 60; 82 | 83 | snprintf_P ( temp, 1500, 84 | PSTR("\ 85 | \ 86 | \ 87 | ESP8266 Upload\ 88 | \ 89 | \ 90 | \ 91 | \ 92 | \ 93 |
\ 94 | \ 95 | \ 96 | \ 97 |
\ 98 | \ 99 | "), 100 | hr, min % 60, sec % 60 101 | ); 102 | server.send ( 200, "text/html", temp ); 103 | } 104 | 105 | void handleNotFound() { 106 | String message = "File Not Found\n\n"; 107 | message += "URI: "; 108 | message += server.uri(); 109 | message += "\nMethod: "; 110 | message += ( server.method() == HTTP_GET ) ? "GET" : "POST"; 111 | message += "\nArguments: "; 112 | message += server.args(); 113 | message += "\n"; 114 | for ( uint8_t i = 0; i < server.args(); i++ ) { 115 | message += " " + server.argName ( i ) + ": " + server.arg ( i ) + "\n"; 116 | } 117 | server.send ( 404, "text/plain", message ); 118 | } 119 | 120 | char* listStatusJSON() { 121 | char json[512]; 122 | File file; 123 | openPaletteFileWithIndex(currentPaletteIndex, &file); 124 | snprintf_P(json, sizeof(json), PSTR("{\"mode\":%d, \"FPS\":%d,\"show_length\":%d, \"ftb_speed\":%d, \"overall_brightness\":%d, \"effect_brightness\":%d, \"color\":[%d, %d, %d], \"glitter_color\":[%d,%d,%d], \"glitter_density\":%d, \"glitter_on\":%d, \"confetti_density\":%d, \"palette_name\": \"%s\", \"glitter_wipe_on\": %d, \"num_leds\":%d, \"max_current\":%d}"), settings.mode, settings.fps, settings.show_length, settings.ftb_speed, settings.overall_brightness, settings.effect_brightness, settings.main_color.red, settings.main_color.green, settings.main_color.blue, settings.glitter_color.red, settings.glitter_color.green, settings.glitter_color.blue, settings.glitter_density, settings.glitter_on, settings.confetti_dens, file.name(), settings.glitter_wipe_on, settings.num_leds, settings.max_current); 125 | file.close(); 126 | return json; 127 | } 128 | 129 | 130 | void getStatusJSON() { 131 | server.send ( 200, "application/json", listStatusJSON() ); 132 | } 133 | 134 | void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { 135 | switch (type) { 136 | case WStype_DISCONNECTED: 137 | DBG_OUTPUT_PORT.printf("WS: [%u] Disconnected!\n", num); 138 | break; 139 | 140 | case WStype_CONNECTED: { 141 | IPAddress ip = webSocket.remoteIP(num); 142 | DBG_OUTPUT_PORT.printf("WS: [%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload); 143 | 144 | // send message to client 145 | webSocket.sendTXT(num, "Connected"); 146 | } 147 | break; 148 | 149 | case WStype_TEXT: 150 | DBG_OUTPUT_PORT.printf("WS: [%u] get Text: %s\n", num, payload); 151 | 152 | // # ==> Set main color 153 | if (payload[0] == '#') { 154 | // decode rgb data 155 | uint32_t rgb = (uint32_t) strtol((const char *) &payload[1], NULL, 16); 156 | settings.main_color.red = ((rgb >> 16) & 0xFF); 157 | settings.main_color.green = ((rgb >> 8) & 0xFF); 158 | settings.main_color.blue = ((rgb >> 0) & 0xFF); 159 | DBG_OUTPUT_PORT.printf("Set main color to: [%u] [%u] [%u]\n", settings.main_color.red, settings.main_color.green, settings.main_color.blue); 160 | webSocket.sendTXT(num, "OK"); 161 | } 162 | 163 | // # ==> Set glitter color 164 | if (payload[0] == 'G') { 165 | // decode rgb data 166 | uint32_t rgb = (uint32_t) strtol((const char *) &payload[1], NULL, 16); 167 | settings.glitter_color.red = ((rgb >> 16) & 0xFF); 168 | settings.glitter_color.green = ((rgb >> 8) & 0xFF); 169 | settings.glitter_color.blue = ((rgb >> 0) & 0xFF); 170 | DBG_OUTPUT_PORT.printf("Set glitter color to: [%u] [%u] [%u]\n", settings.glitter_color.red, settings.glitter_color.green, settings.glitter_color.blue); 171 | webSocket.sendTXT(num, "OK"); 172 | } 173 | 174 | // # ==> Set delay 175 | if (payload[0] == '?') { 176 | // decode delay data 177 | uint8_t d = (uint8_t) strtol((const char *) &payload[1], NULL, 10); 178 | settings.fps = ((d >> 0) & 0xFF); 179 | if (settings.fps == 0) settings.fps = 1; // Prevent divide by zero. 180 | DBG_OUTPUT_PORT.printf("WS: Set FPS: [%u]\n", settings.fps); 181 | webSocket.sendTXT(num, "OK"); 182 | } 183 | 184 | // # ==> Set brightness 185 | if (payload[0] == '%') { 186 | uint8_t b = (uint8_t) strtol((const char *) &payload[1], NULL, 10); 187 | settings.overall_brightness = ((b >> 0) & 0xFF); 188 | DBG_OUTPUT_PORT.printf("WS: Set brightness to: [%u]\n", settings.overall_brightness); 189 | FastLED.setBrightness(settings.overall_brightness); 190 | webSocket.sendTXT(num, "OK"); 191 | } 192 | 193 | // e ==> Set effect brightness 194 | if (payload[0] == 'e') { 195 | uint8_t b = (uint8_t) strtol((const char *) &payload[1], NULL, 10); 196 | settings.effect_brightness = ((b >> 0) & 0xFF); 197 | DBG_OUTPUT_PORT.printf("WS: Set effect brightness to: [%u]\n", settings.effect_brightness); 198 | webSocket.sendTXT(num, "OK"); 199 | } 200 | 201 | // # ==> Set show_length 202 | if (payload[0] == '^') { 203 | uint8_t b = (uint8_t) strtol((const char *) &payload[1], NULL, 10); 204 | settings.show_length = ((b >> 0) & 0xFF); 205 | DBG_OUTPUT_PORT.printf("WS: Set show_length to: [%u]\n", settings.show_length); 206 | webSocket.sendTXT(num, "OK"); 207 | } 208 | 209 | // # ==> Set fade to black speed 210 | if (payload[0] == '_') { 211 | uint8_t b = (uint8_t) strtol((const char *) &payload[1], NULL, 10); 212 | settings.ftb_speed = ((b >> 0) & 0xFF); 213 | DBG_OUTPUT_PORT.printf("WS: Set fade to black speed to: [%u]\n", settings.ftb_speed); 214 | webSocket.sendTXT(num, "OK"); 215 | } 216 | 217 | // # ==> Set number of LEDs 218 | if (payload[0] == '&') { 219 | uint16_t b = (uint16_t) strtol((const char *) &payload[1], NULL, 10); 220 | if (b <= 0) { 221 | b=1; 222 | } 223 | 224 | settings.num_leds = b; 225 | DBG_OUTPUT_PORT.printf("WS: Set number of leds to: [%u]\n", settings.num_leds); 226 | saveSettings(); 227 | webSocket.sendTXT(num, "OK"); 228 | } 229 | 230 | // # ==> Set maximum LED string current 231 | if (payload[0] == '<') { 232 | uint16_t b = (uint16_t) strtol((const char *) &payload[1], NULL, 10); 233 | if (b <= 10) { 234 | b = 10; 235 | } 236 | 237 | settings.max_current = b; 238 | DBG_OUTPUT_PORT.printf("WS: Set LED current to: [%u]\n", settings.max_current); 239 | saveSettings(); 240 | webSocket.sendTXT(num, "OK"); 241 | } 242 | 243 | // # ==> Set fade glitter density 244 | if (payload[0] == '+') { 245 | uint8_t b = (uint8_t) strtol((const char *) &payload[1], NULL, 10); 246 | settings.glitter_density = ((b >> 0) & 0xFF); 247 | DBG_OUTPUT_PORT.printf("WS: Set fade to glitter density to: [%u]\n", settings.glitter_density); 248 | webSocket.sendTXT(num, "OK"); 249 | } 250 | 251 | 252 | // * ==> Set main color and light all LEDs (Shortcut) 253 | if (payload[0] == '*') { 254 | // decode rgb data 255 | uint32_t rgb = (uint32_t) strtol((const char *) &payload[1], NULL, 16); 256 | 257 | settings.main_color.red = ((rgb >> 16) & 0xFF); 258 | settings.main_color.green = ((rgb >> 8) & 0xFF); 259 | settings.main_color.blue = ((rgb >> 0) & 0xFF); 260 | 261 | for (int i = 0; i < settings.num_leds; i++) { 262 | leds[i] = CRGB(settings.main_color.red, settings.main_color.green, settings.main_color.blue); 263 | } 264 | FastLED.show(); 265 | DBG_OUTPUT_PORT.printf("WS: Set all leds to main color: [%u] [%u] [%u]\n", settings.main_color.red, settings.main_color.green, settings.main_color.blue); 266 | //exit_func = true; 267 | settings.mode = ALL; 268 | webSocket.sendTXT(num, "OK"); 269 | } 270 | 271 | // ! ==> Set single LED in given color 272 | if (payload[0] == '!') { 273 | // decode led index 274 | uint64_t rgb = (uint64_t) strtol((const char *) &payload[1], NULL, 16); 275 | 276 | uint8_t led = ((rgb >> 24) & 0xFF); 277 | if (led < settings.num_leds) { 278 | ledstates[led].red = ((rgb >> 16) & 0xFF); 279 | ledstates[led].green = ((rgb >> 8) & 0xFF); 280 | ledstates[led].blue = ((rgb >> 0) & 0xFF); 281 | DBG_OUTPUT_PORT.printf("WS: Set single led [%u] to [%u] [%u] [%u]!\n", led, ledstates[led].red, ledstates[led].green, ledstates[led].blue); 282 | 283 | for (uint8_t i = 0; i < settings.num_leds; i++) { 284 | leds[i] = CRGB(ledstates[i].red, ledstates[i].green, ledstates[i].blue); 285 | 286 | } 287 | FastLED.show(); 288 | } 289 | //exit_func = true; 290 | settings.mode = ALL; 291 | webSocket.sendTXT(num, "OK"); 292 | } 293 | 294 | // ! ==> Activate mode 295 | if (payload[0] == '=') { 296 | // we get mode data 297 | String str_mode = String((char *) &payload[0]); 298 | 299 | //exit_func = true; 300 | 301 | if (str_mode.startsWith("=off")) { 302 | settings.mode = OFF; 303 | } 304 | if (str_mode.startsWith("=all")) { 305 | settings.mode = ALL; 306 | } 307 | if (str_mode.startsWith("=mixedshow")) { 308 | settings.mode = MIXEDSHOW; 309 | } 310 | if (str_mode.startsWith("=rainbow")) { 311 | settings.mode = RAINBOW; 312 | } 313 | if (str_mode.startsWith("=confetti")) { 314 | settings.mode = CONFETTI; 315 | } 316 | if (str_mode.startsWith("=sinelon")) { 317 | settings.mode = SINELON; 318 | } 319 | if (str_mode.startsWith("=juggle")) { 320 | settings.mode = JUGGLE; 321 | } 322 | if (str_mode.startsWith("=bpm")) { 323 | settings.mode = BPM; 324 | } 325 | if (str_mode.startsWith("=palette_anims")) { 326 | if (settings.palette_ndx != -1) { 327 | currentPaletteIndex = settings.palette_ndx; 328 | loadPaletteFromFile(settings.palette_ndx, &targetPalette); 329 | } 330 | settings.mode = PALETTE_ANIMS; 331 | } 332 | if (str_mode.startsWith("=ripple")) { 333 | settings.mode = RIPPLE; 334 | } 335 | if (str_mode.startsWith("=comet")) { 336 | settings.mode = COMET; 337 | } 338 | if (str_mode.startsWith("=theaterchase")) { 339 | settings.mode = THEATERCHASE; 340 | } 341 | if (str_mode.startsWith("=add_glitter")) { 342 | settings.glitter_on = true; 343 | } 344 | if (str_mode.startsWith("=stop_glitter")) { 345 | settings.glitter_on = false; 346 | } 347 | if (str_mode.startsWith("=start_glitter_wipe")) { 348 | settings.glitter_wipe_on = true; 349 | } 350 | if (str_mode.startsWith("=stop_glitter_wipe")) { 351 | settings.glitter_wipe_on = false; 352 | } 353 | if (str_mode.startsWith("=wipe")) { 354 | settings.mode = WIPE; 355 | } 356 | if (str_mode.startsWith("=tv")) { 357 | settings.mode = TV; 358 | } 359 | if (str_mode.startsWith("=fire")) { 360 | settings.mode = FIRE; 361 | } 362 | if (str_mode.startsWith("=frainbow")) { 363 | settings.mode = FIRE_RAINBOW; 364 | } 365 | if (str_mode.startsWith("=fworks")) { 366 | settings.mode = FIREWORKS; 367 | } 368 | if (str_mode.startsWith("=fwsingle")) { 369 | settings.mode = FIREWORKS_SINGLE; 370 | } 371 | if (str_mode.startsWith("=fwrainbow")) { 372 | settings.mode = FIREWORKS_RAINBOW; 373 | } 374 | DBG_OUTPUT_PORT.printf("Activated mode [%u]!\n", settings.mode); 375 | webSocket.sendTXT(num, "OK"); 376 | } 377 | 378 | // $ ==> Get status Info. 379 | if (payload[0] == '$') { 380 | DBG_OUTPUT_PORT.printf("Get status info."); 381 | 382 | String json = listStatusJSON(); 383 | DBG_OUTPUT_PORT.println(json); 384 | webSocket.sendTXT(num, json); 385 | } 386 | 387 | // ` ==> Restore defaults. 388 | if (payload[0] == '`') { 389 | DBG_OUTPUT_PORT.printf("Restore defaults."); 390 | loadDefaults(); 391 | String json = listStatusJSON(); 392 | DBG_OUTPUT_PORT.println(json); 393 | webSocket.sendTXT(num, json); 394 | } 395 | 396 | // | ==> Save settings. 397 | if (payload[0] == '|') { 398 | DBG_OUTPUT_PORT.printf("Save settings."); 399 | saveSettings(); 400 | webSocket.sendTXT(num, "OK"); 401 | } 402 | 403 | // \ ==> Load settings. 404 | if (payload[0] == '\\') { 405 | DBG_OUTPUT_PORT.printf("Load settings."); 406 | readSettings(false); 407 | 408 | String json = listStatusJSON(); 409 | DBG_OUTPUT_PORT.println(json); 410 | webSocket.sendTXT(num, json); 411 | } 412 | 413 | // { ==> Change palette 414 | if (payload[0] == '{') { 415 | if (length == 2) { 416 | if (payload[1] == '+') { 417 | DBG_OUTPUT_PORT.printf("Current pallet_ndx=%d\n", settings.palette_ndx); 418 | settings.palette_ndx++; 419 | if (settings.palette_ndx >= paletteCount) { 420 | settings.palette_ndx = 0; 421 | } 422 | 423 | targetPaletteIndex = settings.palette_ndx; 424 | loadPaletteFromFile(settings.palette_ndx, &targetPalette); 425 | 426 | if (settings.glitter_wipe_on) { 427 | wipeInProgress = true; 428 | } 429 | 430 | DBG_OUTPUT_PORT.printf("Next palette: %d\n", settings.palette_ndx); 431 | } else if (payload[1] == '-') { 432 | DBG_OUTPUT_PORT.printf("Current pallet_ndx=%d\n", settings.palette_ndx); 433 | settings.palette_ndx--; 434 | if (settings.palette_ndx < 0) { 435 | settings.palette_ndx = paletteCount-1; 436 | } 437 | 438 | targetPaletteIndex = settings.palette_ndx; 439 | loadPaletteFromFile(settings.palette_ndx, &targetPalette); 440 | 441 | if (settings.glitter_wipe_on) { 442 | wipeInProgress = true; 443 | } 444 | DBG_OUTPUT_PORT.printf("Next palette: %d\n", settings.palette_ndx); 445 | } else if (payload[1] == 'r') { 446 | DBG_OUTPUT_PORT.printf("Randomize palette.\n"); 447 | settings.palette_ndx = -1; 448 | ChangePalettePeriodically(true); 449 | } else if (payload[1] == 'd') { 450 | DBG_OUTPUT_PORT.printf("Change direction: %d\n", anim_direction); 451 | anim_direction = (DIRECTION)!anim_direction; 452 | } 453 | } 454 | String json = listStatusJSON(); 455 | DBG_OUTPUT_PORT.println(json); 456 | webSocket.sendTXT(num, json); 457 | } 458 | 459 | // " ==> Confetti Density 460 | if (payload[0] == '"') { 461 | uint8_t b = (uint8_t) strtol((const char *) &payload[1], NULL, 10); 462 | settings.confetti_dens = ((b >> 0) & 0xFF); 463 | DBG_OUTPUT_PORT.printf("WS: Set confetti density to: [%u]\n", settings.confetti_dens); 464 | webSocket.sendTXT(num, "OK"); 465 | } 466 | break; 467 | } 468 | } 469 | 470 | void checkForRequests() { 471 | webSocket.loop(); 472 | server.handleClient(); 473 | } 474 | -------------------------------------------------------------------------------- /spiffs_webserver.h: -------------------------------------------------------------------------------- 1 | // *************************************************************************** 2 | // SPIFFS Webserver 3 | // Source: https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266WebServer/examples/FSBrowser 4 | // *************************************************************************** 5 | 6 | /* 7 | FSWebServer - Example WebServer with SPIFFS backend for esp8266 8 | Copyright (c) 2015 Hristo Gochkov. All rights reserved. 9 | This file is part of the ESP8266WebServer library for Arduino environment. 10 | This library is free software; you can redistribute it and/or 11 | modify it under the terms of the GNU Lesser General Public 12 | License as published by the Free Software Foundation; either 13 | version 2.1 of the License, or (at your option) any later version. 14 | This library is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | Lesser General Public License for more details. 18 | You should have received a copy of the GNU Lesser General Public 19 | License along with this library; if not, write to the Free Software 20 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 | upload the contents of the data folder with MkSPIFFS Tool ("ESP8266 Sketch Data Upload" in Tools menu in Arduino IDE) 22 | or you can upload the contents of a folder if you CD in that folder and run the following command: 23 | for file in `ls -A1`; do curl -F "file=@$PWD/$file" esp8266fs.local/edit; done 24 | access the sample web page at http://esp8266fs.local 25 | edit the page by going to http://esp8266fs.local/edit 26 | */ 27 | 28 | File fsUploadFile; 29 | 30 | //format bytes 31 | String formatBytes(size_t bytes) { 32 | if (bytes < 1024) { 33 | return String(bytes) + "B"; 34 | } else if (bytes < (1024 * 1024)) { 35 | return String(bytes / 1024.0) + "KB"; 36 | } else if (bytes < (1024 * 1024 * 1024)) { 37 | return String(bytes / 1024.0 / 1024.0) + "MB"; 38 | } else { 39 | return String(bytes / 1024.0 / 1024.0 / 1024.0) + "GB"; 40 | } 41 | } 42 | 43 | String getContentType(String filename) { 44 | if (server.hasArg("download")) return "application/octet-stream"; 45 | else if (filename.endsWith(".htm")) return "text/html"; 46 | else if (filename.endsWith(".html")) return "text/html"; 47 | else if (filename.endsWith(".css")) return "text/css"; 48 | else if (filename.endsWith(".js")) return "application/javascript"; 49 | else if (filename.endsWith(".png")) return "image/png"; 50 | else if (filename.endsWith(".gif")) return "image/gif"; 51 | else if (filename.endsWith(".jpg")) return "image/jpeg"; 52 | else if (filename.endsWith(".ico")) return "image/x-icon"; 53 | else if (filename.endsWith(".xml")) return "text/xml"; 54 | else if (filename.endsWith(".pdf")) return "application/x-pdf"; 55 | else if (filename.endsWith(".zip")) return "application/x-zip"; 56 | else if (filename.endsWith(".gz")) return "application/x-gzip"; 57 | return "text/plain"; 58 | } 59 | 60 | bool handleFileRead(String path) { 61 | DBG_OUTPUT_PORT.println("handleFileRead: " + path); 62 | if (path.endsWith("/")) path += "index.htm"; 63 | String contentType = getContentType(path); 64 | String pathWithGz = path + ".gz"; 65 | if (SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)) { 66 | if (SPIFFS.exists(pathWithGz)) 67 | path += ".gz"; 68 | File file = SPIFFS.open(path, "r"); 69 | size_t sent = server.streamFile(file, contentType); 70 | file.close(); 71 | return true; 72 | } 73 | return false; 74 | } 75 | 76 | void handleFileUpload() { 77 | if (server.uri() != "/edit") return; 78 | HTTPUpload& upload = server.upload(); 79 | if (upload.status == UPLOAD_FILE_START) { 80 | String filename = upload.filename; 81 | if (!filename.startsWith("/")) filename = "/" + filename; 82 | DBG_OUTPUT_PORT.print("handleFileUpload Name: "); 83 | DBG_OUTPUT_PORT.println(filename); 84 | fsUploadFile = SPIFFS.open(filename, "w"); 85 | filename = String(); 86 | } else if (upload.status == UPLOAD_FILE_WRITE) { 87 | //DBG_OUTPUT_PORT.print("handleFileUpload Data: "); DBG_OUTPUT_PORT.println(upload.currentSize); 88 | if (fsUploadFile) 89 | fsUploadFile.write(upload.buf, upload.currentSize); 90 | } else if (upload.status == UPLOAD_FILE_END) { 91 | if (fsUploadFile) 92 | fsUploadFile.close(); 93 | DBG_OUTPUT_PORT.print("handleFileUpload Size: "); DBG_OUTPUT_PORT.println(upload.totalSize); 94 | } 95 | 96 | // Update the paletteCount in case someone uploaded one. 97 | paletteCount = getPaletteCount(); 98 | 99 | } 100 | 101 | void handleFileDelete() { 102 | if (server.args() == 0) return server.send(500, "text/plain", "BAD ARGS"); 103 | String path = server.arg(0); 104 | DBG_OUTPUT_PORT.println("handleFileDelete: " + path); 105 | if (path == "/") 106 | return server.send(500, "text/plain", "BAD PATH"); 107 | if (!SPIFFS.exists(path)) 108 | return server.send(404, "text/plain", "FileNotFound"); 109 | SPIFFS.remove(path); 110 | server.send(200, "text/plain", ""); 111 | path = String(); 112 | 113 | // Update the paletteCount in case someone deleted one. 114 | paletteCount = getPaletteCount(); 115 | 116 | } 117 | 118 | void handleFileCreate() { 119 | if (server.args() == 0) 120 | return server.send(500, "text/plain", "BAD ARGS"); 121 | String path = server.arg(0); 122 | DBG_OUTPUT_PORT.println("handleFileCreate: " + path); 123 | if (path == "/") 124 | return server.send(500, "text/plain", "BAD PATH"); 125 | if (SPIFFS.exists(path)) 126 | return server.send(500, "text/plain", "FILE EXISTS"); 127 | File file = SPIFFS.open(path, "w"); 128 | if (file) 129 | file.close(); 130 | else 131 | return server.send(500, "text/plain", "CREATE FAILED"); 132 | server.send(200, "text/plain", ""); 133 | path = String(); 134 | 135 | // Update the paletteCount in case someone created one. 136 | paletteCount = getPaletteCount(); 137 | } 138 | 139 | void handleFileList() { 140 | if (!server.hasArg("dir")) { 141 | server.send(500, "text/plain", "BAD ARGS"); 142 | return; 143 | } 144 | 145 | String path = server.arg("dir"); 146 | DBG_OUTPUT_PORT.println("handleFileList: " + path); 147 | Dir dir = SPIFFS.openDir(path); 148 | path = String(); 149 | 150 | String output = "["; 151 | while (dir.next()) { 152 | File entry = dir.openFile("r"); 153 | if (output != "[") output += ','; 154 | bool isDir = false; 155 | output += "{\"type\":\""; 156 | output += (isDir) ? "dir" : "file"; 157 | output += "\",\"name\":\""; 158 | output += String(entry.name()).substring(1); 159 | output += "\"}"; 160 | entry.close(); 161 | } 162 | 163 | output += "]"; 164 | server.send(200, "text/json", output); 165 | } 166 | --------------------------------------------------------------------------------