#include #include "FastLED.h" #include #include #include #include "OmWebServer.h" extern "C" { #include "user_interface.h" } // How many leds in your strip? #define NUM_LEDS 120 // For led chips like Neopixels, which have a data line, ground, and power, you just // need to define DATA_PIN. For led chipsets that are SPI based (four wires - data, clock, // ground, and power), like the LPD8806, define both DATA_PIN and CLOCK_PIN #define DATA_PIN D3 #define BUTTON_PIN D2 #define BUTTON_VCC D1 // Network goodies static OmWebServer ows; static OmWebPages tree; static int requestCount; // Define the array of leds static CRGB leds[NUM_LEDS]; static int ticks = 0; // +------------------------------------------- // | Web page stuff // | int webButtonCountdown = 0; // set by a button action. void pressTheButtonAction(int ref1, void *ref2) { webButtonCountdown = ref1; } void ledStatusAction(const char *page, const char *item, int value, int ref1, void *ref2) { int ledPin = ref1 ? BUILTIN_LED : -1; ows.setStatusLedPin(ledPin); } CRGB overrideColor; int overrideColorCountdown = 0; void goColorAction(int ref1, void *ref2) { overrideColor = CRGB((ref1 >> 16) & 0xff,(ref1 >> 8) & 0xff,(ref1 >> 0) & 0xff); overrideColorCountdown = 1000; } void goColorAction2(const char *pageName, const char *itemName, int value, int ref1, void *ref2) { overrideColor = CRGB((ref1 >> 16) & 0xff,(ref1 >> 8) & 0xff,(ref1 >> 0) & 0xff); overrideColorCountdown = 500; } void pressTheButton2Action(const char *pageName, const char *itemName, int value, int ref1, void *ref2) { overrideColorCountdown = 0; if(ref1 < 0) // -1 means momentary { webButtonCountdown = value ? 3000 : 0; // on, then off. } else { webButtonCountdown = ref1; } } void headerProc(OmXmlWriter &w, int ref1, void *ref2) { w.beginElement("h1"); w.beginElement("center"); w.addContent("IFL Electronics Zone \"E\""); w.endElement(); w.endElement(); } void footerProc(OmXmlWriter &w, int ref1, void *ref2) { w.addElement("hr"); tree.renderPageButton(w, "home"); tree.renderPageButton(w, "info"); tree.renderPageButton(w, "control"); } void showInfo(OmXmlWriter &w, int ref1, void *ref2) { w.addElement("hr"); w.beginElement("pre"); w.addContentF("uptime: %s\n", omTime(millis())); w.addContentF("requests: %d\n", tree.requestsAll); w.addContentF("paramReqs: %d\n", tree.requestsParam); w.addContentF("frames: %d\n", ticks); w.addContentF("freeBytes: %d\n", system_get_free_heap_size()); w.addContentF("chipId: 0x%08x\n", system_get_chip_id()); w.addContentF("systemSdk: %s[%d]\n", system_get_sdk_version(), system_get_boot_version()); w.addContentF("longestHtml: %d\n", tree.greatestRenderLength); w.addContentF("serverIp: %s:%d\n", omIpToString(ows.getIp()), ows.getPort()); w.addContentF("clientIp: %s:%d\n", omIpToString(ows.getClientIp()), ows.getClientPort()); w.endElement(); } int cHue = 50; int cSaturation = 100; int cBrightness = 50; void sliderProc(const char *pageName, const char *itemName, int value, int ref1, void *ref2) { if(omStringEqual(itemName, "hue")) { cHue = value; } if(omStringEqual(itemName, "saturation")) { cSaturation = value; } if(omStringEqual(itemName, "brightness")) { cBrightness = value; } overrideColor = CHSV(cHue * 255 / 100, cSaturation * 255 / 100, cBrightness * 255 / 100); overrideColorCountdown = 700; } void setUpMenuTree() { tree.setHeaderProc(headerProc); tree.setFooterProc(footerProc); tree.beginPage("control"); tree.addButton("singleDot", pressTheButton2Action, -1); tree.addButton("red", goColorAction2, 0xFF0000); tree.addButton("magenta", goColorAction2, 0xFF00FF); tree.addButton("cyan", goColorAction2, 0x00FFFF); tree.addButton("yellow", goColorAction2, 0xFFFF00); tree.addButton("white", goColorAction2, 0xFFFFFF); tree.addPageLink("sliders"); tree.addButton("disable_led_status", ledStatusAction, 0); tree.addButton("enable_led_status", ledStatusAction, 1); tree.beginPage("info"); tree.addHtml(showInfo); tree.beginPage("sliders"); tree.addSlider("hue", sliderProc, cHue); tree.addSlider("saturation", sliderProc, cSaturation); tree.addSlider("brightness", sliderProc, cBrightness); OmWebPages *treeP = &tree; } // | // | Web page stuff // +------------------------------------------- static void setPixel(float x, CHSV color) { #if 0 || ALTERNATE_WITH_UNANTIALIASED if (ticks & 0x080) { leds[(int)x] = color; return; } #endif CHSV color2 = color; float t = x - floor(x); color2.value *= t; color.value *= 1.0 - t; int xI = (int)floor(x); if (xI >= 0 && xI < NUM_LEDS) leds[xI] += color; xI++; if (xI >= 0 && xI < NUM_LEDS) leds[xI] += color2; } float randomf(float low, float high) { #define rfk 1000113 float x = random(0, rfk) * (high - low) / (float)rfk + low; return x; } float migrate(float x, float amount, float towards) { float del = towards - x; if (abs(del) <= amount) x = towards; else if (del < 0) x -= amount; else x += amount; return x; } class Sparkle { public: int active; float x; float rate; CHSV color; Sparkle() { this->x = 0; this->rate = 1; this->color = CHSV(0, 255, 255); } Sparkle(float x, float rate, int hue) { this->x = x; this->rate = rate; this->color.hue = hue; this->color.saturation = 255; this->color.value = 255; this->active = 1; } int tick(float moveAmount) { if (this->active) { this->x += moveAmount; if (x < 0 || x >= NUM_LEDS) { active = 0; } else { setPixel(this->x, this->color); } } return this->active; } int tick() { this->tick(this->rate); return this->active; } int tickTowards(float amount, float towards) { this->x = migrate(this->x, amount, towards); this->tick(0); return this->active; } }; #define SPARKLE_COUNT 50 Sparkle sparkles[SPARKLE_COUNT]; void connectionStatus(const char *ssid, bool trying, bool failure, bool success) { if(success) { String bonjourName = "ezone";// + system_get_chip_id(); MDNS.begin(bonjourName.c_str()); Serial.printf("(*) Bonjour address: http://%s.local\n", bonjourName.c_str()); } } void setup() { Serial.begin(115200); Serial.print("\n\n\n\n\nHello Idea Fab Labs Giant Letter E\n"); setUpMenuTree(); ows.addWifi("Idea Fab Labs", "vortexrings"); ows.addWifi("omino warp", "0123456789"); ows.setHandler(tree); ows.setStatusCallback(connectionStatus); ows.begin(); LEDS.addLeds(leds, NUM_LEDS); LEDS.setBrightness(220); for (int i = 0; i < SPARKLE_COUNT; i++) { sparkles[i] = Sparkle(0, randomf(0.03, 0.3), random(0, 256)); sparkles[i].active = 0; } pinMode(BUTTON_PIN, INPUT_PULLUP); // set pin to input pinMode(BUTTON_VCC, OUTPUT); // used to ground the button ha ha digitalWrite(BUTTON_VCC, 0); } void fadeall() { for (int i = 0; i < NUM_LEDS; i++) { leds[i].nscale8(250); } } void clear() { for (int i = 0; i < NUM_LEDS; i++) { leds[i] = CRGB(0, 0, 0); } } bool wasButton; int buttonDest = NUM_LEDS / 2; unsigned long int lastMillis = 0; void loop() { delay(10); ticks++; ows.tick(); clear(); // if we got a web page "color override", respect that for a while. if(overrideColorCountdown > 0) { CRGB color = overrideColor; int scale = overrideColorCountdown / 2; if(scale > 255) scale = 255; color.nscale8(scale); overrideColorCountdown--; int spacing = 5; int offset = (ticks / 1) % spacing; for(int ix = 0; ix < NUM_LEDS; ix++) { if( (ix + offset) % spacing == 0) leds[ix] = color; } FastLED.show(); return; } bool isButton = !digitalRead(BUTTON_PIN); if (webButtonCountdown > 0) { isButton = true; webButtonCountdown--; } if (isButton && !wasButton) { buttonDest = random(10, NUM_LEDS - 10); } wasButton = isButton; if (isButton) { for (int ix = 0; ix < SPARKLE_COUNT; ix++) { sparkles[ix].tickTowards(2.3, buttonDest); } FastLED.show(); return; } for (int ix = 0; ix < SPARKLE_COUNT; ix++) { Sparkle &s = sparkles[ix]; s.tick(); if (s.active == 0 && random(1, 20) == 2) { int dir = random(0, 2); s.x = randomf(0, 2); s.x = dir ? s.x : NUM_LEDS - 1 - s.x; float maxRate = 0.4; if (random(1, 20) == 2) maxRate = 2; s.rate = randomf(0.05, maxRate) * (dir ? +1 : -1); s.color.hue = random(0, 256); s.color.value = random(40, 220); s.active = 1; } } FastLED.show(); }