// Cocktail Lights Device Code #require "Promise.lib.nut:4.0.0" // This is the total number of LEDs on the Sign const NUMPIXELS = 179; // Use this to set an auto-shut off MAX_TIME_ON <- 120 * 1000; // 2 minutes BUTTON_TIMEOUT <- 60 * 1000 * 60 * 60 * 3; // 3 hours // Amount of seconds to stay on each light pattern PATTERN_TIME_SEC <- 15; //Debug for firmware issues server.log("Device started (version: " + imp.getsoftwareversion() + ")"); // constants for using SPI to emulate 1-wire const BYTESPERPIXEL = 27; const BYTESPERCOLOR = 9; // BYTESPERPIXEL / 3 const SPICLK = 7500; // SPI clock speed in kHz const DELAY = 0.025; // For NeoPixel Latching // this string contains the "equivalent waveform" to send the numbers 0-255 over SPI at 7.5MHz. // 9 bytes of string are required to send 1 byte of emulated 1-wire data. // For example, to add a byte containing the number "14" to the frame: // bits.slice(14 * 9, (14 * 9) + 9); bits <- ["\xE0\x70\x38\x1C\x0E\x07\x03\x81\xC0", "\xE0\x70\x38\x1C\x0E\x07\x03\x81\xF8", "\xE0\x70\x38\x1C\x0E\x07\x03\xF1\xC0", "\xE0\x70\x38\x1C\x0E\x07\x03\xF1\xF8", "\xE0\x70\x38\x1C\x0E\x07\xE3\x81\xC0", "\xE0\x70\x38\x1C\x0E\x07\xE3\x81\xF8", "\xE0\x70\x38\x1C\x0E\x07\xE3\xF1\xC0", "\xE0\x70\x38\x1C\x0E\x07\xE3\xF1\xF8", "\xE0\x70\x38\x1C\x0F\xC7\x03\x81\xC0", "\xE0\x70\x38\x1C\x0F\xC7\x03\x81\xF8", "\xE0\x70\x38\x1C\x0F\xC7\x03\xF1\xC0", "\xE0\x70\x38\x1C\x0F\xC7\x03\xF1\xF8", "\xE0\x70\x38\x1C\x0F\xC7\xE3\x81\xC0", "\xE0\x70\x38\x1C\x0F\xC7\xE3\x81\xF8", "\xE0\x70\x38\x1C\x0F\xC7\xE3\xF1\xC0", "\xE0\x70\x38\x1C\x0F\xC7\xE3\xF1\xF8", "\xE0\x70\x38\x1F\x8E\x07\x03\x81\xC0", "\xE0\x70\x38\x1F\x8E\x07\x03\x81\xF8", "\xE0\x70\x38\x1F\x8E\x07\x03\xF1\xC0", "\xE0\x70\x38\x1F\x8E\x07\x03\xF1\xF8", "\xE0\x70\x38\x1F\x8E\x07\xE3\x81\xC0", "\xE0\x70\x38\x1F\x8E\x07\xE3\x81\xF8", "\xE0\x70\x38\x1F\x8E\x07\xE3\xF1\xC0", "\xE0\x70\x38\x1F\x8E\x07\xE3\xF1\xF8", "\xE0\x70\x38\x1F\x8F\xC7\x03\x81\xC0", "\xE0\x70\x38\x1F\x8F\xC7\x03\x81\xF8", "\xE0\x70\x38\x1F\x8F\xC7\x03\xF1\xC0", "\xE0\x70\x38\x1F\x8F\xC7\x03\xF1\xF8", "\xE0\x70\x38\x1F\x8F\xC7\xE3\x81\xC0", "\xE0\x70\x38\x1F\x8F\xC7\xE3\x81\xF8", "\xE0\x70\x38\x1F\x8F\xC7\xE3\xF1\xC0", "\xE0\x70\x38\x1F\x8F\xC7\xE3\xF1\xF8", "\xE0\x70\x3F\x1C\x0E\x07\x03\x81\xC0", "\xE0\x70\x3F\x1C\x0E\x07\x03\x81\xF8", "\xE0\x70\x3F\x1C\x0E\x07\x03\xF1\xC0", "\xE0\x70\x3F\x1C\x0E\x07\x03\xF1\xF8", "\xE0\x70\x3F\x1C\x0E\x07\xE3\x81\xC0", "\xE0\x70\x3F\x1C\x0E\x07\xE3\x81\xF8", "\xE0\x70\x3F\x1C\x0E\x07\xE3\xF1\xC0", "\xE0\x70\x3F\x1C\x0E\x07\xE3\xF1\xF8", "\xE0\x70\x3F\x1C\x0F\xC7\x03\x81\xC0", "\xE0\x70\x3F\x1C\x0F\xC7\x03\x81\xF8", "\xE0\x70\x3F\x1C\x0F\xC7\x03\xF1\xC0", "\xE0\x70\x3F\x1C\x0F\xC7\x03\xF1\xF8", "\xE0\x70\x3F\x1C\x0F\xC7\xE3\x81\xC0", "\xE0\x70\x3F\x1C\x0F\xC7\xE3\x81\xF8", "\xE0\x70\x3F\x1C\x0F\xC7\xE3\xF1\xC0", "\xE0\x70\x3F\x1C\x0F\xC7\xE3\xF1\xF8", "\xE0\x70\x3F\x1F\x8E\x07\x03\x81\xC0", "\xE0\x70\x3F\x1F\x8E\x07\x03\x81\xF8", "\xE0\x70\x3F\x1F\x8E\x07\x03\xF1\xC0", "\xE0\x70\x3F\x1F\x8E\x07\x03\xF1\xF8", "\xE0\x70\x3F\x1F\x8E\x07\xE3\x81\xC0", "\xE0\x70\x3F\x1F\x8E\x07\xE3\x81\xF8", "\xE0\x70\x3F\x1F\x8E\x07\xE3\xF1\xC0", "\xE0\x70\x3F\x1F\x8E\x07\xE3\xF1\xF8", "\xE0\x70\x3F\x1F\x8F\xC7\x03\x81\xC0", "\xE0\x70\x3F\x1F\x8F\xC7\x03\x81\xF8", "\xE0\x70\x3F\x1F\x8F\xC7\x03\xF1\xC0", "\xE0\x70\x3F\x1F\x8F\xC7\x03\xF1\xF8", "\xE0\x70\x3F\x1F\x8F\xC7\xE3\x81\xC0", "\xE0\x70\x3F\x1F\x8F\xC7\xE3\x81\xF8", "\xE0\x70\x3F\x1F\x8F\xC7\xE3\xF1\xC0", "\xE0\x70\x3F\x1F\x8F\xC7\xE3\xF1\xF8", "\xE0\x7E\x38\x1C\x0E\x07\x03\x81\xC0", "\xE0\x7E\x38\x1C\x0E\x07\x03\x81\xF8", "\xE0\x7E\x38\x1C\x0E\x07\x03\xF1\xC0", "\xE0\x7E\x38\x1C\x0E\x07\x03\xF1\xF8", "\xE0\x7E\x38\x1C\x0E\x07\xE3\x81\xC0", "\xE0\x7E\x38\x1C\x0E\x07\xE3\x81\xF8", "\xE0\x7E\x38\x1C\x0E\x07\xE3\xF1\xC0", "\xE0\x7E\x38\x1C\x0E\x07\xE3\xF1\xF8", "\xE0\x7E\x38\x1C\x0F\xC7\x03\x81\xC0", "\xE0\x7E\x38\x1C\x0F\xC7\x03\x81\xF8", "\xE0\x7E\x38\x1C\x0F\xC7\x03\xF1\xC0", "\xE0\x7E\x38\x1C\x0F\xC7\x03\xF1\xF8", "\xE0\x7E\x38\x1C\x0F\xC7\xE3\x81\xC0", "\xE0\x7E\x38\x1C\x0F\xC7\xE3\x81\xF8", "\xE0\x7E\x38\x1C\x0F\xC7\xE3\xF1\xC0", "\xE0\x7E\x38\x1C\x0F\xC7\xE3\xF1\xF8", "\xE0\x7E\x38\x1F\x8E\x07\x03\x81\xC0", "\xE0\x7E\x38\x1F\x8E\x07\x03\x81\xF8", "\xE0\x7E\x38\x1F\x8E\x07\x03\xF1\xC0", "\xE0\x7E\x38\x1F\x8E\x07\x03\xF1\xF8", "\xE0\x7E\x38\x1F\x8E\x07\xE3\x81\xC0", "\xE0\x7E\x38\x1F\x8E\x07\xE3\x81\xF8", "\xE0\x7E\x38\x1F\x8E\x07\xE3\xF1\xC0", "\xE0\x7E\x38\x1F\x8E\x07\xE3\xF1\xF8", "\xE0\x7E\x38\x1F\x8F\xC7\x03\x81\xC0", "\xE0\x7E\x38\x1F\x8F\xC7\x03\x81\xF8", "\xE0\x7E\x38\x1F\x8F\xC7\x03\xF1\xC0", "\xE0\x7E\x38\x1F\x8F\xC7\x03\xF1\xF8", "\xE0\x7E\x38\x1F\x8F\xC7\xE3\x81\xC0", "\xE0\x7E\x38\x1F\x8F\xC7\xE3\x81\xF8", "\xE0\x7E\x38\x1F\x8F\xC7\xE3\xF1\xC0", "\xE0\x7E\x38\x1F\x8F\xC7\xE3\xF1\xF8", "\xE0\x7E\x3F\x1C\x0E\x07\x03\x81\xC0", "\xE0\x7E\x3F\x1C\x0E\x07\x03\x81\xF8", "\xE0\x7E\x3F\x1C\x0E\x07\x03\xF1\xC0", "\xE0\x7E\x3F\x1C\x0E\x07\x03\xF1\xF8", "\xE0\x7E\x3F\x1C\x0E\x07\xE3\x81\xC0", "\xE0\x7E\x3F\x1C\x0E\x07\xE3\x81\xF8", "\xE0\x7E\x3F\x1C\x0E\x07\xE3\xF1\xC0", "\xE0\x7E\x3F\x1C\x0E\x07\xE3\xF1\xF8", "\xE0\x7E\x3F\x1C\x0F\xC7\x03\x81\xC0", "\xE0\x7E\x3F\x1C\x0F\xC7\x03\x81\xF8", "\xE0\x7E\x3F\x1C\x0F\xC7\x03\xF1\xC0", "\xE0\x7E\x3F\x1C\x0F\xC7\x03\xF1\xF8", "\xE0\x7E\x3F\x1C\x0F\xC7\xE3\x81\xC0", "\xE0\x7E\x3F\x1C\x0F\xC7\xE3\x81\xF8", "\xE0\x7E\x3F\x1C\x0F\xC7\xE3\xF1\xC0", "\xE0\x7E\x3F\x1C\x0F\xC7\xE3\xF1\xF8", "\xE0\x7E\x3F\x1F\x8E\x07\x03\x81\xC0", "\xE0\x7E\x3F\x1F\x8E\x07\x03\x81\xF8", "\xE0\x7E\x3F\x1F\x8E\x07\x03\xF1\xC0", "\xE0\x7E\x3F\x1F\x8E\x07\x03\xF1\xF8", "\xE0\x7E\x3F\x1F\x8E\x07\xE3\x81\xC0", "\xE0\x7E\x3F\x1F\x8E\x07\xE3\x81\xF8", "\xE0\x7E\x3F\x1F\x8E\x07\xE3\xF1\xC0", "\xE0\x7E\x3F\x1F\x8E\x07\xE3\xF1\xF8", "\xE0\x7E\x3F\x1F\x8F\xC7\x03\x81\xC0", "\xE0\x7E\x3F\x1F\x8F\xC7\x03\x81\xF8", "\xE0\x7E\x3F\x1F\x8F\xC7\x03\xF1\xC0", "\xE0\x7E\x3F\x1F\x8F\xC7\x03\xF1\xF8", "\xE0\x7E\x3F\x1F\x8F\xC7\xE3\x81\xC0", "\xE0\x7E\x3F\x1F\x8F\xC7\xE3\x81\xF8", "\xE0\x7E\x3F\x1F\x8F\xC7\xE3\xF1\xC0", "\xE0\x7E\x3F\x1F\x8F\xC7\xE3\xF1\xF8", "\xFC\x70\x38\x1C\x0E\x07\x03\x81\xC0", "\xFC\x70\x38\x1C\x0E\x07\x03\x81\xF8", "\xFC\x70\x38\x1C\x0E\x07\x03\xF1\xC0", "\xFC\x70\x38\x1C\x0E\x07\x03\xF1\xF8", "\xFC\x70\x38\x1C\x0E\x07\xE3\x81\xC0", "\xFC\x70\x38\x1C\x0E\x07\xE3\x81\xF8", "\xFC\x70\x38\x1C\x0E\x07\xE3\xF1\xC0", "\xFC\x70\x38\x1C\x0E\x07\xE3\xF1\xF8", "\xFC\x70\x38\x1C\x0F\xC7\x03\x81\xC0", "\xFC\x70\x38\x1C\x0F\xC7\x03\x81\xF8", "\xFC\x70\x38\x1C\x0F\xC7\x03\xF1\xC0", "\xFC\x70\x38\x1C\x0F\xC7\x03\xF1\xF8", "\xFC\x70\x38\x1C\x0F\xC7\xE3\x81\xC0", "\xFC\x70\x38\x1C\x0F\xC7\xE3\x81\xF8", "\xFC\x70\x38\x1C\x0F\xC7\xE3\xF1\xC0", "\xFC\x70\x38\x1C\x0F\xC7\xE3\xF1\xF8", "\xFC\x70\x38\x1F\x8E\x07\x03\x81\xC0", "\xFC\x70\x38\x1F\x8E\x07\x03\x81\xF8", "\xFC\x70\x38\x1F\x8E\x07\x03\xF1\xC0", "\xFC\x70\x38\x1F\x8E\x07\x03\xF1\xF8", "\xFC\x70\x38\x1F\x8E\x07\xE3\x81\xC0", "\xFC\x70\x38\x1F\x8E\x07\xE3\x81\xF8", "\xFC\x70\x38\x1F\x8E\x07\xE3\xF1\xC0", "\xFC\x70\x38\x1F\x8E\x07\xE3\xF1\xF8", "\xFC\x70\x38\x1F\x8F\xC7\x03\x81\xC0", "\xFC\x70\x38\x1F\x8F\xC7\x03\x81\xF8", "\xFC\x70\x38\x1F\x8F\xC7\x03\xF1\xC0", "\xFC\x70\x38\x1F\x8F\xC7\x03\xF1\xF8", "\xFC\x70\x38\x1F\x8F\xC7\xE3\x81\xC0", "\xFC\x70\x38\x1F\x8F\xC7\xE3\x81\xF8", "\xFC\x70\x38\x1F\x8F\xC7\xE3\xF1\xC0", "\xFC\x70\x38\x1F\x8F\xC7\xE3\xF1\xF8", "\xFC\x70\x3F\x1C\x0E\x07\x03\x81\xC0", "\xFC\x70\x3F\x1C\x0E\x07\x03\x81\xF8", "\xFC\x70\x3F\x1C\x0E\x07\x03\xF1\xC0", "\xFC\x70\x3F\x1C\x0E\x07\x03\xF1\xF8", "\xFC\x70\x3F\x1C\x0E\x07\xE3\x81\xC0", "\xFC\x70\x3F\x1C\x0E\x07\xE3\x81\xF8", "\xFC\x70\x3F\x1C\x0E\x07\xE3\xF1\xC0", "\xFC\x70\x3F\x1C\x0E\x07\xE3\xF1\xF8", "\xFC\x70\x3F\x1C\x0F\xC7\x03\x81\xC0", "\xFC\x70\x3F\x1C\x0F\xC7\x03\x81\xF8", "\xFC\x70\x3F\x1C\x0F\xC7\x03\xF1\xC0", "\xFC\x70\x3F\x1C\x0F\xC7\x03\xF1\xF8", "\xFC\x70\x3F\x1C\x0F\xC7\xE3\x81\xC0", "\xFC\x70\x3F\x1C\x0F\xC7\xE3\x81\xF8", "\xFC\x70\x3F\x1C\x0F\xC7\xE3\xF1\xC0", "\xFC\x70\x3F\x1C\x0F\xC7\xE3\xF1\xF8", "\xFC\x70\x3F\x1F\x8E\x07\x03\x81\xC0", "\xFC\x70\x3F\x1F\x8E\x07\x03\x81\xF8", "\xFC\x70\x3F\x1F\x8E\x07\x03\xF1\xC0", "\xFC\x70\x3F\x1F\x8E\x07\x03\xF1\xF8", "\xFC\x70\x3F\x1F\x8E\x07\xE3\x81\xC0", "\xFC\x70\x3F\x1F\x8E\x07\xE3\x81\xF8", "\xFC\x70\x3F\x1F\x8E\x07\xE3\xF1\xC0", "\xFC\x70\x3F\x1F\x8E\x07\xE3\xF1\xF8", "\xFC\x70\x3F\x1F\x8F\xC7\x03\x81\xC0", "\xFC\x70\x3F\x1F\x8F\xC7\x03\x81\xF8", "\xFC\x70\x3F\x1F\x8F\xC7\x03\xF1\xC0", "\xFC\x70\x3F\x1F\x8F\xC7\x03\xF1\xF8", "\xFC\x70\x3F\x1F\x8F\xC7\xE3\x81\xC0", "\xFC\x70\x3F\x1F\x8F\xC7\xE3\x81\xF8", "\xFC\x70\x3F\x1F\x8F\xC7\xE3\xF1\xC0", "\xFC\x70\x3F\x1F\x8F\xC7\xE3\xF1\xF8", "\xFC\x7E\x38\x1C\x0E\x07\x03\x81\xC0", "\xFC\x7E\x38\x1C\x0E\x07\x03\x81\xF8", "\xFC\x7E\x38\x1C\x0E\x07\x03\xF1\xC0", "\xFC\x7E\x38\x1C\x0E\x07\x03\xF1\xF8", "\xFC\x7E\x38\x1C\x0E\x07\xE3\x81\xC0", "\xFC\x7E\x38\x1C\x0E\x07\xE3\x81\xF8", "\xFC\x7E\x38\x1C\x0E\x07\xE3\xF1\xC0", "\xFC\x7E\x38\x1C\x0E\x07\xE3\xF1\xF8", "\xFC\x7E\x38\x1C\x0F\xC7\x03\x81\xC0", "\xFC\x7E\x38\x1C\x0F\xC7\x03\x81\xF8", "\xFC\x7E\x38\x1C\x0F\xC7\x03\xF1\xC0", "\xFC\x7E\x38\x1C\x0F\xC7\x03\xF1\xF8", "\xFC\x7E\x38\x1C\x0F\xC7\xE3\x81\xC0", "\xFC\x7E\x38\x1C\x0F\xC7\xE3\x81\xF8", "\xFC\x7E\x38\x1C\x0F\xC7\xE3\xF1\xC0", "\xFC\x7E\x38\x1C\x0F\xC7\xE3\xF1\xF8", "\xFC\x7E\x38\x1F\x8E\x07\x03\x81\xC0", "\xFC\x7E\x38\x1F\x8E\x07\x03\x81\xF8", "\xFC\x7E\x38\x1F\x8E\x07\x03\xF1\xC0", "\xFC\x7E\x38\x1F\x8E\x07\x03\xF1\xF8", "\xFC\x7E\x38\x1F\x8E\x07\xE3\x81\xC0", "\xFC\x7E\x38\x1F\x8E\x07\xE3\x81\xF8", "\xFC\x7E\x38\x1F\x8E\x07\xE3\xF1\xC0", "\xFC\x7E\x38\x1F\x8E\x07\xE3\xF1\xF8", "\xFC\x7E\x38\x1F\x8F\xC7\x03\x81\xC0", "\xFC\x7E\x38\x1F\x8F\xC7\x03\x81\xF8", "\xFC\x7E\x38\x1F\x8F\xC7\x03\xF1\xC0", "\xFC\x7E\x38\x1F\x8F\xC7\x03\xF1\xF8", "\xFC\x7E\x38\x1F\x8F\xC7\xE3\x81\xC0", "\xFC\x7E\x38\x1F\x8F\xC7\xE3\x81\xF8", "\xFC\x7E\x38\x1F\x8F\xC7\xE3\xF1\xC0", "\xFC\x7E\x38\x1F\x8F\xC7\xE3\xF1\xF8", "\xFC\x7E\x3F\x1C\x0E\x07\x03\x81\xC0", "\xFC\x7E\x3F\x1C\x0E\x07\x03\x81\xF8", "\xFC\x7E\x3F\x1C\x0E\x07\x03\xF1\xC0", "\xFC\x7E\x3F\x1C\x0E\x07\x03\xF1\xF8", "\xFC\x7E\x3F\x1C\x0E\x07\xE3\x81\xC0", "\xFC\x7E\x3F\x1C\x0E\x07\xE3\x81\xF8", "\xFC\x7E\x3F\x1C\x0E\x07\xE3\xF1\xC0", "\xFC\x7E\x3F\x1C\x0E\x07\xE3\xF1\xF8", "\xFC\x7E\x3F\x1C\x0F\xC7\x03\x81\xC0", "\xFC\x7E\x3F\x1C\x0F\xC7\x03\x81\xF8", "\xFC\x7E\x3F\x1C\x0F\xC7\x03\xF1\xC0", "\xFC\x7E\x3F\x1C\x0F\xC7\x03\xF1\xF8", "\xFC\x7E\x3F\x1C\x0F\xC7\xE3\x81\xC0", "\xFC\x7E\x3F\x1C\x0F\xC7\xE3\x81\xF8", "\xFC\x7E\x3F\x1C\x0F\xC7\xE3\xF1\xC0", "\xFC\x7E\x3F\x1C\x0F\xC7\xE3\xF1\xF8", "\xFC\x7E\x3F\x1F\x8E\x07\x03\x81\xC0", "\xFC\x7E\x3F\x1F\x8E\x07\x03\x81\xF8", "\xFC\x7E\x3F\x1F\x8E\x07\x03\xF1\xC0", "\xFC\x7E\x3F\x1F\x8E\x07\x03\xF1\xF8", "\xFC\x7E\x3F\x1F\x8E\x07\xE3\x81\xC0", "\xFC\x7E\x3F\x1F\x8E\x07\xE3\x81\xF8", "\xFC\x7E\x3F\x1F\x8E\x07\xE3\xF1\xC0", "\xFC\x7E\x3F\x1F\x8E\x07\xE3\xF1\xF8", "\xFC\x7E\x3F\x1F\x8F\xC7\x03\x81\xC0", "\xFC\x7E\x3F\x1F\x8F\xC7\x03\x81\xF8", "\xFC\x7E\x3F\x1F\x8F\xC7\x03\xF1\xC0", "\xFC\x7E\x3F\x1F\x8F\xC7\x03\xF1\xF8", "\xFC\x7E\x3F\x1F\x8F\xC7\xE3\x81\xC0", "\xFC\x7E\x3F\x1F\x8F\xC7\xE3\x81\xF8", "\xFC\x7E\x3F\x1F\x8F\xC7\xE3\xF1\xC0", "\xFC\x7E\x3F\x1F\x8F\xC7\xE3\xF1\xF8"]; // This string holds three "zero" bytes [0,0,0]; clears a pixel when written to the frame const clearString = "\xE0\x70\x38\x1C\x0E\x07\x03\x81\xC0\xE0\x70\x38\x1C\x0E\x07\x03\x81\xC0\xE0\x70\x38\x1C\x0E\x07\x03\x81\xC0"; /* CLASS AND FUNCTION DEFINITIONS --------------------------------------------*/ class neoPixels { spi = null; frameSize = null; frame = null; // _spi - A configured spi (MSB_FIRST, 7.5MHz) // _frameSize - Number of Pixels per frame constructor(_spi, _frameSize) { this.spi = _spi; this.frameSize = _frameSize; this.frame = blob(frameSize*27 + 1); clearFrame(); writeFrame(); } // sets a pixel in the frame buffer // but does not write it to the pixel strip // color is an array of the form [r, g, b] function writePixel(p, color) { frame.seek(p*BYTESPERPIXEL); // red and green are swapped for some reason, so swizzle them back frame.writestring(bits[color[1]]); frame.writestring(bits[color[0]]); frame.writestring(bits[color[2]]); } // Clears the frame buffer // but does not write it to the pixel strip function clearFrame() { frame.seek(0); for (local p = 0; p < frameSize; p++) frame.writestring(clearString); frame.writen(0x00,'c'); } // writes the frame buffer to the pixel strip // ie - this function changes the pixel strip function writeFrame() { spi.write(frame); } } class Button{ static NORMALLY_HIGH = 1; static NORMALLY_LOW = 0; _pin = null; _pull = null; _polarity = null; _pressCallback = null; _releaseCallback = null; constructor(pin, pull, polarity, pressCallback, releaseCallback){ _pin = pin; //Unconfigured IO pin, eg hardware.pin2 _pull = pull; //DIGITAL_IN_PULLDOWN, DIGITAL_IN or DIGITAL_IN_PULLUP _polarity = polarity; //Normal button state, ie 1 if button is pulled up and the button shorts to GND _pressCallback = pressCallback; //Function to call on a button press (may be null) _releaseCallback = releaseCallback; //Function to call on a button release (may be null) _pin.configure(_pull, debounce.bindenv(this)); } function debounce(){ _pin.configure(_pull); imp.wakeup(0.010, getState.bindenv(this)); //Based on googling, bounce times are usually limited to 10ms } function getState(){ if( _polarity == _pin.read() ){ if(_releaseCallback != null){ _releaseCallback(); } }else{ if(_pressCallback != null){ _pressCallback(); } } _pin.configure(_pull, debounce.bindenv(this)); } } ///////////////////////////////// //////////// Our Code /////////// ///////////////////////////////// GREEN <- [0x88,0x00,0x00]; RED <- [0x00,0x88,0x00]; ORANGE <- [0x20,0x88,0x00]; BLUE <- [0x00,0x00,0x88]; PURPLE <- [0x00,0x88,0x88]; AQUA <- [0x55,0x00,0x45]; WHITE <- [0x88,0x88,0x88]; BLACK <- [0,0,0]; // Our output pin for NeoPixel will be last SPI number (7) spi <- hardware.spi257; spi.configure(MSB_FIRST, SPICLK); pixelStrip <- neoPixels(spi, NUMPIXELS); // Brightness Controll pot <- hardware.pin8; pot.configure(ANALOG_IN); SHOW_LIGHTS <- true; START_TIME <- hardware.millis(); local loopTimer = null; function turn_off_after(){ if(hardware.millis() - START_TIME > MAX_TIME_ON){ server.log("Got Timeout. Going to Sleep"); SHOW_LIGHTS = false; } } function startButtonPress() { server.log("Start Press"); SHOW_LIGHTS = true; // Restart our timeout counters imp.cancelwakeup(loopTimer); next_pattern(); START_TIME = hardware.millis(); // Reset Loop vars reset_light_patterns(); // On a button press, we'll extend the on time MAX_TIME_ON = BUTTON_TIMEOUT; // 3 hours } function remoteStart(msg) { startButtonPress(); } function stopButtonPress() { server.log("Stop Press"); SHOW_LIGHTS = false; } function remoteStop(msg) { stopButtonPress(); } // Util function to set the color of the all the neopixels function setColor(color) { pixelStrip.clearFrame(); pixelStrip.writeFrame(); for (local i=0; i high){ return high; } if (input < low){ return low; } return input } ////// Light Pattern: lightUpInOrder ////// last_led <- 0; last_time <- hardware.millis(); led_color <- [0x22, 0x22, 0] // This will get over written by pot function lightUpInOrder(){ // don't do anything if we haven't hit our delay if ((hardware.millis() - last_time) >= 5){ last_led += 1; checkBrightness(); for(local i=0; i < NUMPIXELS; i++){ if (i <= last_led){ pixelStrip.writePixel(i, led_color); } else { pixelStrip.writePixel(i, BLACK); } } pixelStrip.writeFrame(); if (last_led >= NUMPIXELS){ last_led = 0; // Extra delay to stay on after last pixel last_time = hardware.millis() + (3 * 1000); } else { last_time = hardware.millis(); } } } ////// Light Pattern: lightUpEvenOdds ////// current_count <- 0; going_up <- true; function lightUpEvenOdds(){ // don't do anything if we haven't hit our delay if ((hardware.millis() - last_time) >= 1){ checkBrightness(); local mid = led_color[0] / 2; local color_even = mid + (current_count * 1); local color_odd = mid - (current_count * 1); color_even = fix(color_even, 0, led_color[0]); color_odd = fix(color_odd, 0, led_color[0]); for(local i=0; i < NUMPIXELS; i++){ if (i % 2){ pixelStrip.writePixel(i, [color_odd, color_odd, 0]); } else { pixelStrip.writePixel(i, [color_even, color_even, 0]); } } pixelStrip.writeFrame(); if (going_up){ current_count += 1; } else { current_count -= 1; } if(current_count >= 32) { going_up = false; } if(current_count <= -32) { going_up = true; } last_time = hardware.millis() } } ////// Light Pattern: lightUpFlashLetters ////// letters_start <- [0,20,44,64,91,107,131,143,156]; letters_end <- [20,44,64,91,107,131,143,156,179]; current_letter <- -1; function lightUpFlashLetters(){ // don't do anything if we haven't hit our delay if ((hardware.millis() - last_time) > 500){ letters <- letters_end.len(); current_letter += 1; if (current_letter >= letters){ current_letter = 0; } checkBrightness(); pixelStrip.clearFrame(); pixelStrip.writeFrame(); for(local i=letters_start[current_letter]; i < letters_end[current_letter]; i++){ pixelStrip.writePixel(i, led_color); } pixelStrip.writeFrame(); last_time = hardware.millis() } } // Used for light patterns to set brightness from controller board function checkBrightness(){ // This should max the reading at 64, but we'll check bright <- pot.read() / 1000; bright = fix(bright, 0, 64); // The number below is the dimest the light will get led_color[0] = 0x11 + bright; led_color[1] = 0x11 + bright; } function reset_light_patterns(){ last_led = 0; current_count = 0; current_letter = -1; MAIN_PATTERN = -1; last_time = hardware.millis(); } ////// Loop for Light Patterns ////// MAIN_PATTERN <- -1; MAIN_IS_BLACK <- false; function next_pattern(){ MAIN_PATTERN += 1; // Sets the time in seconds before switching patterns loopTimer = imp.wakeup(PATTERN_TIME_SEC, next_pattern); } ////// Here's where the magic happens ////// function main(){ if(SHOW_LIGHTS){ // Pick which pattern to show switch (MAIN_PATTERN) { case 0: lightUpInOrder(); break; case 1: lightUpEvenOdds(); break; case 2: lightUpFlashLetters(); break; default: server.log("Starting Pattern Over"); reset_light_patterns(); MAIN_PATTERN = 0; } MAIN_IS_BLACK = false; turn_off_after(); } else { // We should go dark and conserve power if (MAIN_IS_BLACK == false){ setColor(BLACK); MAIN_IS_BLACK = true; } // This saves a few amps of current // but also slightly less responsive to wakeup imp.sleep(0.200); } imp.wakeup(0.00001, main); } // Start our call back functions next_pattern(); main(); // Setup our input buttons button_start <- Button(hardware.pin1, DIGITAL_IN_PULLUP, Button.NORMALLY_HIGH, startButtonPress, startButtonPress ); button_stop <- Button(hardware.pin9, DIGITAL_IN_PULLUP, Button.NORMALLY_HIGH, stopButtonPress, stopButtonPress ); // Register the remote agent callbacks agent.on("StartLights", remoteStart); agent.on("StopLights", remoteStop); ////////////// Code for Offline Alerts /////// /////// Ping/pong Code //////// function pong(foo){ //agent.send("pong",imp.getmacaddress()); } agent.on("ping",pong); pong(1); /////// Disconnect Handling ////// server.setsendtimeoutpolicy(RETURN_ON_ERROR, WAIT_TIL_SENT, 10); function disconnectionHandler(reason) { if (reason != SERVER_CONNECTED) { // Attempt to reconnect in 2 minutes' time imp.wakeup(120, reconnect); } else { server.log("Device reconncted"); } } function reconnect() { server.connect(disconnectionHandler, 60); } // Register the unexpected disconnect handler server.onunexpecteddisconnect(disconnectionHandler);