Skip to content

Instantly share code, notes, and snippets.

@AlexJWayne
Created November 6, 2014 04:36
Show Gist options
  • Save AlexJWayne/57c7414074fb8cbeaec0 to your computer and use it in GitHub Desktop.
Save AlexJWayne/57c7414074fb8cbeaec0 to your computer and use it in GitHub Desktop.
// 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