BlinkenLights.ino 11.7 KB
Newer Older
Mitchell Pomery's avatar
Mitchell Pomery committed
1
/**
Mitchell Pomery's avatar
Mitchell Pomery committed
2 3
 BlinkenLights
 
Mitchell Pomery's avatar
Mitchell Pomery committed
4 5 6 7 8 9
 Code by Mitchell Pomery [BG3] with help from Andrew Adamson [BOB]
 Hardware by Andrew Adamson [BOB] with help from Mitchell Pomery [BG3]
 
 Get the dates from the git commits.
 
 The LED strip should be wired from the top left corner and zig zag down
Mitchell Pomery's avatar
Mitchell Pomery committed
10 11 12 13 14 15
 
 */

///TODO: Vary light pattern randomly
///TODO: Make run when no network is present
///TODO: Recover when network reappears
Mitchell Pomery's avatar
Mitchell Pomery committed
16
///TODO: Make everything use posts. maybe
Mitchell Pomery's avatar
Mitchell Pomery committed
17 18
///TODO: Sanity checks. Everywhere. Until I'm Insane.
///TODO: Figure out memory usage. If we max memory we will see weird behaviour.
Mitchell Pomery's avatar
Mitchell Pomery committed
19 20 21 22 23 24 25 26 27 28 29

#include <Ethernet.h> // Needed For Reasons
#include <WebServer.h> // Lets us easily do web requests
#include <SPI.h> // Needed to control Lights
#include <Adafruit_NeoPixel.h> // Controls the Lights

#define PIN 6 // Pin that the LED strip is attached to
#define PREFIX "" // Document root for our pages
#define PORT 80 // Web Server Port
#define NAMELEN 8 // Max variable length in request
#define VALUELEN 256 // Max value from request
Mitchell Pomery's avatar
Mitchell Pomery committed
30 31 32
#define WIDTH 7 // How many LEDs wide our array is
#define HEIGHT 6 // How many LEDs high our array is
#define STRIPLENGTH 42 // Number of LED's in light strip
Mitchell Pomery's avatar
Mitchell Pomery committed
33 34 35 36 37 38 39 40

// Used to store the LED's values
struct led {
  char red;
  char green;
  char blue;
};

Mitchell Pomery's avatar
Mitchell Pomery committed
41
// For controlling the lights - Should only be changed by the functions
Mitchell Pomery's avatar
Mitchell Pomery committed
42 43
int position = 0; // How far through the cycle we are
struct led ledArray[STRIPLENGTH]; // led array
Mitchell Pomery's avatar
Mitchell Pomery committed
44
int lightOption = 0; // Which predefined light sequence we are running
Mitchell Pomery's avatar
Mitchell Pomery committed
45 46 47
char brightness = (char) 128; //Brightness of the LEDs
  // We seem to have issues at the moment putting this up to the maximum (255)
  // Most likely due to the fact the LED strip is underpowered
Mitchell Pomery's avatar
Mitchell Pomery committed
48

Mitchell Pomery's avatar
Mitchell Pomery committed
49
// Network Settings
Mitchell Pomery's avatar
Mitchell Pomery committed
50
static uint8_t mac[] = { 0xC0, 0xCA, 0xC0, 0x1A, 0x19, 0x82 }; // C0CA C01A 1982
Mitchell Pomery's avatar
Mitchell Pomery committed
51
IPAddress ip(130,95,13,96); // 130.95.13.96 (Can we forcefully take .82?
Mitchell Pomery's avatar
Mitchell Pomery committed
52
// If we remove the ip address, we will automatically use DHCP
Mitchell Pomery's avatar
Mitchell Pomery committed
53 54 55 56 57 58

// Set up our light strip
Adafruit_NeoPixel strip = Adafruit_NeoPixel(STRIPLENGTH, PIN, NEO_GRB + NEO_KHZ800);
// Set up our webserver
WebServer webserver(PREFIX, 80);

Mitchell Pomery's avatar
Mitchell Pomery committed
59 60
// ============================ LIGHT MANIPULATION ============================

Mitchell Pomery's avatar
Mitchell Pomery committed
61 62
/**
 * Change the lights to our updated array
Mitchell Pomery's avatar
Mitchell Pomery committed
63
 * We should probably get rid of this soonish
Mitchell Pomery's avatar
Mitchell Pomery committed
64
 */
Mitchell Pomery's avatar
Mitchell Pomery committed
65
void showArray() {
Mitchell Pomery's avatar
Mitchell Pomery committed
66
  ///TODO: Rename this to something better?
Mitchell Pomery's avatar
Mitchell Pomery committed
67
  for (int i = 0; i < STRIPLENGTH; i ++) {
Mitchell Pomery's avatar
Mitchell Pomery committed
68
    strip.setPixelColour(i, (int) ledArray[i].red, (int) ledArray[i].green, (int) ledArray[i].blue);
Mitchell Pomery's avatar
Mitchell Pomery committed
69 70 71 72
  }
  strip.show();
}

Mitchell Pomery's avatar
Mitchell Pomery committed
73
/**
Mitchell Pomery's avatar
Mitchell Pomery committed
74
 * go from (x,y) to position in the array
Mitchell Pomery's avatar
Mitchell Pomery committed
75 76
 * @param xpos  x coordinate
 * @param ypos  y cordinate
Mitchell Pomery's avatar
Mitchell Pomery committed
77
 * @return      position in the array, -1 if out of array
Mitchell Pomery's avatar
Mitchell Pomery committed
78 79 80 81
 */
int coordToPos(int xpos, int ypos) {
  ///TODO: Test this function
  int pos = 0;
Mitchell Pomery's avatar
Mitchell Pomery committed
82 83 84
  if ((xpos < 0 || xpos >= WIDTH) || (ypos < 0 || ypos >= HEIGHT)) {
    return -1;
  }
Mitchell Pomery's avatar
Mitchell Pomery committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98
  if (ypos % 2 == 0) { // if we are on an even line, add y
    pos = ypos * WIDTH + xpos;
  }
  else { // on an odd line, take y
    if (WIDTH % 2 == 0) { // even width
      pos = ypos * WIDTH + HEIGHT - xpos;
    }
    else { // odd width
      pos = ypos * WIDTH + HEIGHT - xpos -1;
    }
  }
  return pos;
}

Mitchell Pomery's avatar
Mitchell Pomery committed
99
/**
Mitchell Pomery's avatar
Mitchell Pomery committed
100
 * Set the LED at pos in the strip to the defined colour
Mitchell Pomery's avatar
Mitchell Pomery committed
101
 * @param pos   position in the array
Mitchell Pomery's avatar
Mitchell Pomery committed
102 103 104
 * @param red   red portion of colour
 * @param green green portion of colour
 * @param blue  blue portion of colour
Mitchell Pomery's avatar
Mitchell Pomery committed
105
 */
Mitchell Pomery's avatar
Mitchell Pomery committed
106 107 108 109 110 111
void setLED(int pos, int red, int green, int blue) {
  ledArray[pos].red = red;
  ledArray[pos].green = green;
  ledArray[pos].blue = blue;
}

Mitchell Pomery's avatar
Mitchell Pomery committed
112
/**
Mitchell Pomery's avatar
Mitchell Pomery committed
113
 * Set the LED at (xpos, ypos) in the strip to the defined colour
Mitchell Pomery's avatar
Mitchell Pomery committed
114 115
 * @param xpos  x coordinate
 * @param ypos  y coordinate
Mitchell Pomery's avatar
Mitchell Pomery committed
116 117 118
 * @param red   red portion of colour
 * @param green green portion of colour
 * @param blue  blue portion of colour
Mitchell Pomery's avatar
Mitchell Pomery committed
119
 */
Mitchell Pomery's avatar
Mitchell Pomery committed
120 121
void setLED(int xpos, int ypos, int red, int green, int blue) {
  int pos = coordToPos(xpos, ypos);
Mitchell Pomery's avatar
Mitchell Pomery committed
122 123 124 125
  setLED(pos, red, green, blue);
}

/**
Mitchell Pomery's avatar
Mitchell Pomery committed
126 127
 * Get the colour of the LED in pos position in the strip
 * @param pos   position in the strip
Mitchell Pomery's avatar
Mitchell Pomery committed
128
 * @return      colour of LED at pos
Mitchell Pomery's avatar
Mitchell Pomery committed
129 130 131 132 133
 */
struct led getLED(int pos) {
  return ledArray[pos];
}

Mitchell Pomery's avatar
Mitchell Pomery committed
134 135 136 137
/**
 * Get the colour of the LED at (xpos, ypos)
 * @param xpos  x coordinate
 * @param ypos  y coordinate
Mitchell Pomery's avatar
Mitchell Pomery committed
138
 * @return      colour of LED at (xpos, ypos)
Mitchell Pomery's avatar
Mitchell Pomery committed
139 140 141 142 143 144 145 146 147 148 149 150
 */
struct led getLED(int xpos, int ypos) {
  int pos = coordToPos(xpos, ypos);
  return ledArray[pos];
}

// ================================ WEB PAGES ================================

///TODO: Comment this stuff
///TODO: Reduce code reuse in the web page functions
///TODO: Make a function to set all the lights at once

Mitchell Pomery's avatar
Mitchell Pomery committed
151 152 153 154 155 156 157 158
/**
 * Sets the light sequence to one that is predefined.
 * Set it to 0 to disable the cycling of lights.
 * @param server        
 * @param type          
 * @param url_tail      
 * @param tail_complete 
 */
Mitchell Pomery's avatar
Mitchell Pomery committed
159 160 161 162 163 164
void webSetSequence(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete) {
  URLPARAM_RESULT rc;
  char name[NAMELEN];
  char value[VALUELEN];
  
  server.httpSuccess();
Mitchell Pomery's avatar
Mitchell Pomery committed
165
  // Kill the connection before doing anything if all they want is head
Mitchell Pomery's avatar
Mitchell Pomery committed
166 167 168
  if (type == WebServer::HEAD) {
    return;
  }
Mitchell Pomery's avatar
Mitchell Pomery committed
169
  else if (type == WebServer::GET) {
Mitchell Pomery's avatar
Mitchell Pomery committed
170 171 172 173 174 175 176 177 178 179 180 181 182
    if (strlen(url_tail)) {
      while (strlen(url_tail)) {
        rc = server.nextURLparam(&url_tail, name, NAMELEN, value, VALUELEN);
        if (rc != URLPARAM_EOS) {
          if (String(name).equals("seq")) {
            lightOption = atoi(value);
            server.print(lightOption);
          }
        }
      }
    }
  }
  else {
Mitchell Pomery's avatar
Mitchell Pomery committed
183
    server.print("Unknown Request");
Mitchell Pomery's avatar
Mitchell Pomery committed
184 185 186
  }
}

Mitchell Pomery's avatar
Mitchell Pomery committed
187 188 189 190 191 192 193
/**
 * Set a specific LED to a specific colour
 * @param server        
 * @param type          
 * @param url_tail      
 * @param tail_complete 
 */
Mitchell Pomery's avatar
Mitchell Pomery committed
194 195 196 197 198 199 200 201 202 203 204
void webSetLED(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete) {
  URLPARAM_RESULT rc;
  char name[NAMELEN];
  char value[VALUELEN];
  int xPos = -1;
  int yPos = -1;
  int r = -1;
  int g = -1;
  int b = -1;
  
  server.httpSuccess();
Mitchell Pomery's avatar
Mitchell Pomery committed
205
  // Kill the connection before doing anything if all they want is head
Mitchell Pomery's avatar
Mitchell Pomery committed
206 207 208
  if (type == WebServer::HEAD) {
    return;
  }
Mitchell Pomery's avatar
Mitchell Pomery committed
209
  else if (type == WebServer::GET) {
Mitchell Pomery's avatar
Mitchell Pomery committed
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
    if (strlen(url_tail)) {
      while (strlen(url_tail)) {
        rc = server.nextURLparam(&url_tail, name, NAMELEN, value, VALUELEN);
        if (rc != URLPARAM_EOS) {
          if (String(name).equals("x")) {
            xPos = atoi(value);
          }
          else if (String(name).equals("y")) {
            yPos = atoi(value);
          }
          else if (String(name).equals("r")) {
            r = atoi(value);
          }
          else if (String(name).equals("g")) {
            g = atoi(value);
          }
          else if (String(name).equals("b")) {
            b = atoi(value);
          }
        }
      }
    }
  }
  else {
    server.print("Unknown");
  }
  if (xPos != -1 && yPos != -1 && r != -1 && g != -1 && b != -1) {
    setLED(xPos, r, g, b);
  }
}

Mitchell Pomery's avatar
Mitchell Pomery committed
241 242 243 244 245 246 247
/**
 * Set the brightness to a specific magnitude
 * @param server        
 * @param type          
 * @param url_tail      
 * @param tail_complete 
 */
Mitchell Pomery's avatar
Mitchell Pomery committed
248 249 250 251 252 253
void webSetBrightness(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete) {
  URLPARAM_RESULT rc;
  char name[NAMELEN];
  char value[VALUELEN];
  
  server.httpSuccess();
Mitchell Pomery's avatar
Mitchell Pomery committed
254
  // Kill the connection before doing anything if all they want is head
Mitchell Pomery's avatar
Mitchell Pomery committed
255 256 257 258 259 260 261 262
  if (type == WebServer::HEAD) {
    return;
  }
  else if (type == WebServer::GET) { //WebServer::POST
    if (strlen(url_tail)) {
      while (strlen(url_tail)) {
        rc = server.nextURLparam(&url_tail, name, NAMELEN, value, VALUELEN);
        if (rc != URLPARAM_EOS) {
Mitchell Pomery's avatar
Mitchell Pomery committed
263
          if (String(name).equals("bright")) {
Mitchell Pomery's avatar
Mitchell Pomery committed
264
            strip.setBrightness(atoi(value));
Mitchell Pomery's avatar
Mitchell Pomery committed
265 266
            server.print(atoi(value));
            strip.show();
Mitchell Pomery's avatar
Mitchell Pomery committed
267 268 269 270 271 272 273 274 275 276
          }
        }
      }
    }
  }
  else {
    server.print("Unknown");
  }
}

Mitchell Pomery's avatar
Mitchell Pomery committed
277 278
// ============================== LIGHT DISPLAYS ==============================

Mitchell Pomery's avatar
Mitchell Pomery committed
279 280 281 282 283 284 285
/**
 * Fill the dots one after the other with a colour
 * @param colour colour to fill the array with
 * @param wait  delay between colour changes
 */
void colourWipe(uint32_t c, uint8_t wait) {
  ///TODO: stop this blocking
Mitchell Pomery's avatar
Mitchell Pomery committed
286
  for(uint16_t i=0; i<strip.numPixels(); i++) {
Mitchell Pomery's avatar
Mitchell Pomery committed
287
      strip.setPixelColour(i, c);
Mitchell Pomery's avatar
Mitchell Pomery committed
288 289 290 291 292
      strip.show();
      delay(wait);
  }
}

Mitchell Pomery's avatar
Mitchell Pomery committed
293 294 295 296
/**
 * 
 * @param wait  delay between colour changes
 */
Mitchell Pomery's avatar
Mitchell Pomery committed
297 298
void rainbow(uint8_t wait) {
  uint16_t i, j;
Mitchell Pomery's avatar
Mitchell Pomery committed
299
  
Mitchell Pomery's avatar
Mitchell Pomery committed
300
  for(i=0; i<strip.numPixels(); i++) {
Mitchell Pomery's avatar
Mitchell Pomery committed
301
    strip.setPixelColour(i, Wheel((i+position) & 255));
Mitchell Pomery's avatar
Mitchell Pomery committed
302 303 304 305 306 307
  }
  strip.show();
  delay(wait);
  position++;
}

Mitchell Pomery's avatar
Mitchell Pomery committed
308 309 310 311
/**
 * Slightly different, this makes the rainbow equally distributed throughout
 * @param wait  delay between colour changes
 */
Mitchell Pomery's avatar
Mitchell Pomery committed
312
void rainbowCycle(uint8_t wait) {
Mitchell Pomery's avatar
Mitchell Pomery committed
313
  ///TODO: stop this blocking
Mitchell Pomery's avatar
Mitchell Pomery committed
314 315
  uint16_t i, j;

Mitchell Pomery's avatar
Mitchell Pomery committed
316
  for(j=0; j<256*5; j++) { // 5 cycles of all colours on wheel
Mitchell Pomery's avatar
Mitchell Pomery committed
317
    for(i=0; i< strip.numPixels(); i++) {
Mitchell Pomery's avatar
Mitchell Pomery committed
318
      strip.setPixelColour(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
Mitchell Pomery's avatar
Mitchell Pomery committed
319 320 321 322 323 324
    }
    strip.show();
    delay(wait);
  }
}

Mitchell Pomery's avatar
Mitchell Pomery committed
325 326 327 328 329
/**
 * Theatre-style crawling lights.
 * @param colour colour to fill the array with
 * @param wait  delay between colour changes
 */
Mitchell Pomery's avatar
Mitchell Pomery committed
330
void theaterChase(uint32_t c, uint8_t wait) {
Mitchell Pomery's avatar
Mitchell Pomery committed
331
  ///TODO: stop this blocking
Mitchell Pomery's avatar
Mitchell Pomery committed
332
  for (int j=0; j<10; j++) { // do 10 cycles of chasing
Mitchell Pomery's avatar
Mitchell Pomery committed
333 334
    for (int q=0; q < 3; q++) {
      for (int i=0; i < strip.numPixels(); i=i+3) {
Mitchell Pomery's avatar
Mitchell Pomery committed
335
        strip.setPixelColour(i+q, c); // turn every third pixel on
Mitchell Pomery's avatar
Mitchell Pomery committed
336 337 338 339 340 341
      }
      strip.show();
     
      delay(wait);
     
      for (int i=0; i < strip.numPixels(); i=i+3) {
Mitchell Pomery's avatar
Mitchell Pomery committed
342
        strip.setPixelColour(i+q, 0); // turn every third pixel off
Mitchell Pomery's avatar
Mitchell Pomery committed
343 344 345 346 347
      }
    }
  }
}

Mitchell Pomery's avatar
Mitchell Pomery committed
348 349 350 351
/**
 * Theatre-style crawling lights with rainbow effect
 * @param wait  delay between colour changes
 */
Mitchell Pomery's avatar
Mitchell Pomery committed
352
void theaterChaseRainbow(uint8_t wait) {
Mitchell Pomery's avatar
Mitchell Pomery committed
353 354
  ///TODO: stop this blocking
  for (int j=0; j < 256; j++) { // cycle all 256 colours in the wheel
Mitchell Pomery's avatar
Mitchell Pomery committed
355 356
    for (int q=0; q < 3; q++) {
        for (int i=0; i < strip.numPixels(); i=i+3) {
Mitchell Pomery's avatar
Mitchell Pomery committed
357
          // turn every third pixel on
Mitchell Pomery's avatar
Mitchell Pomery committed
358
          strip.setPixelColour(i+q, Wheel( (i+j) % 255));
Mitchell Pomery's avatar
Mitchell Pomery committed
359 360 361 362 363 364
        }
        strip.show();
       
        delay(wait);
       
        for (int i=0; i < strip.numPixels(); i=i+3) {
Mitchell Pomery's avatar
Mitchell Pomery committed
365
          strip.setPixelColour(i+q, 0); // turn every third pixel off
Mitchell Pomery's avatar
Mitchell Pomery committed
366 367 368 369 370
        }
    }
  }
}

Mitchell Pomery's avatar
Mitchell Pomery committed
371 372 373 374 375 376
/**
 * Input a value 0 to 255 to get a colour value.
 * The colours are a transition r - g - b - back to r.
 * @param WheelPos  Where we currently are in the cycle
 * @return          A new colour
 */
Mitchell Pomery's avatar
Mitchell Pomery committed
377 378
uint32_t Wheel(byte WheelPos) {
  if(WheelPos < 85) {
Mitchell Pomery's avatar
Mitchell Pomery committed
379
   return strip.colour(WheelPos * 3, 255 - WheelPos * 3, 0);
Mitchell Pomery's avatar
Mitchell Pomery committed
380 381
  } else if(WheelPos < 170) {
   WheelPos -= 85;
Mitchell Pomery's avatar
Mitchell Pomery committed
382
   return strip.colour(255 - WheelPos * 3, 0, WheelPos * 3);
Mitchell Pomery's avatar
Mitchell Pomery committed
383 384
  } else {
   WheelPos -= 170;
Mitchell Pomery's avatar
Mitchell Pomery committed
385
   return strip.colour(0, WheelPos * 3, 255 - WheelPos * 3);
Mitchell Pomery's avatar
Mitchell Pomery committed
386 387 388
  }
}

Mitchell Pomery's avatar
Mitchell Pomery committed
389 390
// =============================== MAIN PROGRAM ===============================

Mitchell Pomery's avatar
Mitchell Pomery committed
391 392
///TODO: Comment this stuff

Mitchell Pomery's avatar
Mitchell Pomery committed
393
void setup() {
Mitchell Pomery's avatar
Mitchell Pomery committed
394
  // Start Ethernet
Mitchell Pomery's avatar
Mitchell Pomery committed
395
  Ethernet.begin(mac, ip);
Mitchell Pomery's avatar
Mitchell Pomery committed
396
  // Set up webpages
Mitchell Pomery's avatar
Mitchell Pomery committed
397 398 399 400
  webserver.setDefaultCommand(&webSetSequence);
  webserver.addCommand("custom", &webSetSequence);
  webserver.addCommand("individual", &webSetLED);
  webserver.addCommand("brightness", &webSetBrightness);
Mitchell Pomery's avatar
Mitchell Pomery committed
401
  // Start Webserver
Mitchell Pomery's avatar
Mitchell Pomery committed
402
  webserver.begin();
Mitchell Pomery's avatar
Mitchell Pomery committed
403
  // Turn our lights on
Mitchell Pomery's avatar
Mitchell Pomery committed
404 405 406 407 408 409 410 411
  for (int i = 0; i < STRIPLENGTH; i ++) {
    ledArray[i].red = (char) 128;
    ledArray[i].green = (char) 128;
    ledArray[i].blue = (char) 128;
  }
  
  // Start Lights
  strip.begin();
Mitchell Pomery's avatar
Mitchell Pomery committed
412
  strip.setBrightness(128);
Mitchell Pomery's avatar
Mitchell Pomery committed
413 414 415 416 417 418 419 420 421 422 423
  showArray();
}

void loop()
{
  // process incoming connections one at a time forever
  char buff[64];
  int len = 64;
  webserver.processConnection(buff, &len);
  position = position % 256;
  // Run our light sequence after checking for we requests
Mitchell Pomery's avatar
Mitchell Pomery committed
424 425
  switch (lightOption) {
    case 0: // Don't change the lights at all
Mitchell Pomery's avatar
Mitchell Pomery committed
426
      break;
Mitchell Pomery's avatar
Mitchell Pomery committed
427
    case 1: // Wipe the LED's to Red
Mitchell Pomery's avatar
Mitchell Pomery committed
428
      colourWipe(strip.colour(255, 0, 0), 50); // Red
Mitchell Pomery's avatar
Mitchell Pomery committed
429 430
      break;
    default:
Mitchell Pomery's avatar
Mitchell Pomery committed
431
      lightOption = 1;
Mitchell Pomery's avatar
Mitchell Pomery committed
432
      break;
Mitchell Pomery's avatar
Mitchell Pomery committed
433
  }
Mitchell Pomery's avatar
Mitchell Pomery committed
434
  // Show our lights
Mitchell Pomery's avatar
Mitchell Pomery committed
435 436
  showArray();
}