Created
November 6, 2014 04:36
-
-
Save AlexJWayne/57c7414074fb8cbeaec0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This #include statement was automatically added by the Spark IDE. | |
#include "Adafruit_LEDBackpack.h" | |
// This #include statement was automatically added by the Spark IDE. | |
#include "Adafruit_GFX.h" | |
#include "neopixel/neopixel.h" | |
// IMPORTANT: Set pixel COUNT, PIN and TYPE | |
#define PIXEL_PIN D2 | |
#define PIXEL_COUNT 144 | |
#define PIXEL_TYPE WS2812B | |
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE); | |
Adafruit_AlphaNum4 alpha4 = Adafruit_AlphaNum4(); | |
uint16_t lastTotal = 0; | |
uint8_t huePos = 0; | |
uint8_t leds[PIXEL_COUNT * 3]; | |
void setup() { | |
// Register call that gets triggered when an order is placed. | |
Spark.function("orderPlaced", orderPlaced); | |
// Setup Alpha Numeric display | |
alpha4.begin(0x70); | |
// alpha4.writeDigitAscii(0, 'A'); | |
// delay(5000); | |
// Setup buffer | |
for (uint16_t i = 0; i < PIXEL_COUNT * 3; i++) leds[i] = 0; | |
// Setup LED strip | |
strip.begin(); | |
strip.setBrightness(70); | |
// TEST! | |
orderPlaced("239"); | |
} | |
void loop() { | |
renderQty(lastTotal); | |
delay(1); | |
} | |
int orderPlaced(String bottleCountString) { | |
// Show bright white and fade when we receive an order. | |
flash(); | |
// Parse the new total and save it. | |
uint16_t total = bottleCountString.toInt(); | |
// If new total is less than old total, reset. | |
if (total < lastTotal) lastTotal = 0; | |
// If the difference is large, animate the change quickly. | |
// This happens duing testing. | |
uint8_t delayMs = total - lastTotal > 100 ? 5 : 250; | |
// For each bottle between the old total and the new total, | |
// render the visualization. THis makes it appear to count up. | |
for (uint16_t i = lastTotal; i <= total; i++) { | |
renderQty(i); | |
delay(delayMs); | |
} | |
// Save the new total as the lastTotal. | |
lastTotal = total; | |
return 1; | |
} | |
// returns the number of LEDs required to show 10 cases per dot section. | |
uint8_t getCaseLedCount(uint16_t total) { | |
uint8_t tenCases = total / 120; | |
return tenCases * 3 + (tenCases / 5) * 2 + 4; | |
} | |
// Render the visualization to display a specific total of bottles. | |
void renderQty(uint16_t total) { | |
// Increment the progress bar animation gradients. | |
huePos++; | |
// Tell the alphanumeric display to show the current bottle total. | |
alphaDisplayTotal(total); | |
// Ten Case Dots! | |
renderTenCaseDots(total); | |
// Progress Bar! | |
renderProgressBar(total); | |
// Show it! | |
stripShow(); | |
} | |
// Draw the ten case dots. | |
void renderTenCaseDots(uint16_t total) { | |
uint8_t i = 0; | |
uint8_t tenCases = total / 120; | |
uint8_t caseLedCount = getCaseLedCount(total); | |
uint8_t spaces = 0; | |
// Black everything out to start. | |
for (i = 0; i < getCaseLedCount(total); i++) { | |
stripSetPixelColor(i, 0, 0, 0); | |
} | |
// [..O..O..O..O..O....O..O..O..O..O..] | |
for (i = 0; i < tenCases; i++) { | |
spaces = (i / 5) * 2; | |
uint8_t j = i*3 + 2 + spaces; | |
// [O..] | |
stripSetPixelColor(j + 0, 255, 255, 255); | |
stripSetPixelColor(j + 1, 0, 0, 0); | |
stripSetPixelColor(j + 2, 0, 0, 0); | |
// [..] | |
if (spaces % 5 == 0) { | |
stripSetPixelColor(j + 3, 0, 0, 0); | |
stripSetPixelColor(j + 4, 0, 0, 0); | |
} | |
} | |
// four space buffer between | |
stripSetPixelColor(i*3 + spaces + 5, 0, 0, 0); | |
stripSetPixelColor(i*3 + spaces + 6, 0, 0, 0); | |
} | |
// Draw the wine colored undulating progress bar to the next ten cases. | |
void renderProgressBar(uint16_t total) { | |
// Number of LEDs required for the case count. | |
uint8_t caseLedCount = getCaseLedCount(total); | |
// number of LEDs left to show the progress bar with. | |
uint8_t bottleLedCount = PIXEL_COUNT - caseLedCount; | |
// number of bottles toward the next ten cases | |
uint8_t bottles = total % 120; | |
// The index at which point the progres bar stops. | |
uint8_t limit = caseLedCount + bottleLedCount * bottles / 120; | |
// Reder the pogress bar. | |
for (uint8_t i = caseLedCount; i < PIXEL_COUNT; i++) { | |
// Before the limit, make it pretty! | |
if (i < limit) { | |
stripSetPixelColor(i, | |
255, | |
getProgressBarGreen(i), | |
getProgressBarBlue(i) | |
); | |
// After the limit, it's just black :( | |
} else { | |
stripSetPixelColor(i, 0, 0, 0); | |
} | |
} | |
} | |
// Animate an attention getting flash of white that fades to black | |
void flash() { | |
// fade from white to normal colors. | |
for (uint8_t i = 255; i > 0; i--) { | |
renderTenCaseDots(lastTotal); | |
renderProgressBar(lastTotal); | |
// | |
for (uint8_t j = 0; j < PIXEL_COUNT; j++) { | |
uint8_t r = leds[j*3 + 0]; | |
uint8_t g = leds[j*3 + 1]; | |
uint8_t b = leds[j*3 + 2]; | |
stripSetPixelColor(j, | |
map(i, 0, 255, 255, r), | |
map(i, 0, 255, 255, g), | |
map(i, 0, 255, 255, b) | |
); | |
} | |
delay(2); | |
} | |
} | |
// Set the whole strip to a solid color. | |
void stripShowColor(uint8_t r, uint8_t g, uint8_t b) { | |
for (uint8_t i = 0; i < PIXEL_COUNT; i++) { | |
stripSetPixelColor(i, r, g, b); | |
} | |
stripShow(); | |
} | |
// Display an integer on the 4 character display. | |
void alphaDisplayTotal(uint16_t total) { | |
for (uint8_t i = 0; i < 4; i++) alpha4.writeDigitRaw(i, 0); | |
if (total >= 1000) alphaWriteDigit(0, total / 1000); | |
if (total >= 100) alphaWriteDigit(1, total / 100); | |
if (total >= 10) alphaWriteDigit(2, total / 10); | |
alphaWriteDigit(3, total); | |
alpha4.writeDisplay(); | |
} | |
// Write a single digit to the 4 character display. | |
void alphaWriteDigit(uint8_t i, uint16_t value) { | |
char asciiChar; | |
switch(value % 10) { | |
case 0: asciiChar = '0'; break; | |
case 1: asciiChar = '1'; break; | |
case 2: asciiChar = '2'; break; | |
case 3: asciiChar = '3'; break; | |
case 4: asciiChar = '4'; break; | |
case 5: asciiChar = '5'; break; | |
case 6: asciiChar = '6'; break; | |
case 7: asciiChar = '7'; break; | |
case 8: asciiChar = '8'; break; | |
case 9: asciiChar = '9'; break; | |
} | |
alpha4.writeDigitAscii(i, asciiChar); | |
} | |
uint8_t getProgressBarGreen(uint8_t ledIdx) { | |
return getChannelComponent( | |
ledIdx, | |
127, // midPoint | |
0, // min | |
72, // max | |
3 // frequency | |
); | |
} | |
uint8_t getProgressBarBlue(uint8_t ledIdx) { | |
return getChannelComponent( | |
ledIdx, | |
24, // midPoint | |
96, // min | |
0, // max | |
7 // frequency | |
); | |
} | |
// Generates a loopable animated sawtooth that moves down the strip over time. | |
// | |
// * ledIdx: the led in question | |
// * midPoint: where the peak of the sawtooth is relative to the first valley | |
// * min: value at the valley | |
// * max: value at the peak | |
// * frequency: How many peaks appear in the entire strip | |
// | |
uint8_t getChannelComponent( | |
uint8_t ledIdx, | |
uint8_t midPoint, | |
uint8_t min, | |
uint8_t max, | |
uint8_t frequency | |
) { | |
uint8_t pos = huePos + ledIdx * frequency; | |
if (pos <= midPoint) { | |
return map(pos, 0, midPoint, min, max); | |
} else { | |
return map(pos, midPoint + 1, 255, max, min); | |
} | |
} | |
void stripSetPixelColor(uint8_t i, uint8_t r, uint8_t g, uint8_t b) { | |
leds[i*3 + 0] = r; | |
leds[i*3 + 1] = g; | |
leds[i*3 + 2] = b; | |
} | |
void stripShow() { | |
for (uint8_t i = 0; i < PIXEL_COUNT; i++) { | |
stripSetPixelColor(i, | |
leds[i*3 + 0], | |
leds[i*3 + 1], | |
leds[i*3 + 2] | |
); | |
} | |
stripShow(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment