BlinkenLights.ino 10.7 KB
Newer Older
Mitchell Pomery's avatar
Mitchell Pomery committed
1 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 68 69 70 71 72
  for (int i = 0; i < STRIPLENGTH; i ++) {
    strip.setPixelColor(i, (int) ledArray[i].red, (int) ledArray[i].green, (int) ledArray[i].blue);
  }
  strip.show();
}

Mitchell Pomery's avatar
Mitchell Pomery committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
/**
 * Set the LED at pos in the strip to the defined color
 * @param xpos  x coordinate
 * @param ypos  y cordinate
 * @return      position in the array
 */
int coordToPos(int xpos, int ypos) {
  ///TODO: Test this function
  int pos = 0;
  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
96 97 98 99 100 101 102
/**
 * Set the LED at pos in the strip to the defined color
 * @param pos   position in the array
 * @param red   red portion of color
 * @param green green portion of color
 * @param blue  blue portion of color
 */
Mitchell Pomery's avatar
Mitchell Pomery committed
103 104 105 106 107 108
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
109
/**
Mitchell Pomery's avatar
Mitchell Pomery committed
110 111 112
 * Set the LED at (xpos, ypos) in the strip to the defined color
 * @param xpos  x coordinate
 * @param ypos  y coordinate
Mitchell Pomery's avatar
Mitchell Pomery committed
113 114 115 116
 * @param red   red portion of color
 * @param green green portion of color
 * @param blue  blue portion of color
 */
Mitchell Pomery's avatar
Mitchell Pomery committed
117 118
void setLED(int xpos, int ypos, int red, int green, int blue) {
  int pos = coordToPos(xpos, ypos);
Mitchell Pomery's avatar
Mitchell Pomery committed
119 120 121 122
  setLED(pos, red, green, blue);
}

/**
Mitchell Pomery's avatar
Mitchell Pomery committed
123 124
 * 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
125 126 127 128 129 130
 * @return      color of LED at pos
 */
struct led getLED(int pos) {
  return ledArray[pos];
}

Mitchell Pomery's avatar
Mitchell Pomery committed
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
/**
 * Get the colour of the LED at (xpos, ypos)
 * @param xpos  x coordinate
 * @param ypos  y coordinate
 * @return      color of LED at (xpos, ypos)
 */
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: Start using post requests
///TODO: Make a function to set all the lights at once

Mitchell Pomery's avatar
Mitchell Pomery committed
149 150 151 152 153 154 155
// Sets the light sequence to one that is predefined
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
156
  // Kill the connection before doing anything if all they want is head
Mitchell Pomery's avatar
Mitchell Pomery committed
157 158 159
  if (type == WebServer::HEAD) {
    return;
  }
Mitchell Pomery's avatar
Mitchell Pomery committed
160
  else if (type == WebServer::GET) {
Mitchell Pomery's avatar
Mitchell Pomery committed
161 162 163 164 165 166 167 168 169 170 171 172 173
    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
174
    server.print("Unknown Request");
Mitchell Pomery's avatar
Mitchell Pomery committed
175 176 177 178 179 180 181 182 183 184 185 186 187 188
  }
}

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
189
  // Kill the connection before doing anything if all they want is head
Mitchell Pomery's avatar
Mitchell Pomery committed
190 191 192
  if (type == WebServer::HEAD) {
    return;
  }
Mitchell Pomery's avatar
Mitchell Pomery committed
193
  else if (type == WebServer::GET) {
Mitchell Pomery's avatar
Mitchell Pomery committed
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
    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);
  }
}

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
231
  // Kill the connection before doing anything if all they want is head
Mitchell Pomery's avatar
Mitchell Pomery committed
232 233 234 235 236 237 238 239
  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
240
          if (String(name).equals("bright")) {
Mitchell Pomery's avatar
Mitchell Pomery committed
241
            strip.setBrightness(atoi(value));
Mitchell Pomery's avatar
Mitchell Pomery committed
242 243
            server.print(atoi(value));
            strip.show();
Mitchell Pomery's avatar
Mitchell Pomery committed
244 245 246 247 248 249 250 251 252 253
          }
        }
      }
    }
  }
  else {
    server.print("Unknown");
  }
}

Mitchell Pomery's avatar
Mitchell Pomery committed
254 255 256 257 258
// ============================== LIGHT DISPLAYS ==============================

///TODO: Comment this stuff
///TODO: Make sure these functions don't block. Otherwise web requests are slow

Mitchell Pomery's avatar
Mitchell Pomery committed
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, c);
      strip.show();
      delay(wait);
  }
}

void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, Wheel((i+position) & 255));
  }
  strip.show();
  delay(wait);
  position++;
}

// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

Mitchell Pomery's avatar
Mitchell Pomery committed
292
// Theatre-style crawling lights.
Mitchell Pomery's avatar
Mitchell Pomery committed
293
void theaterChase(uint32_t c, uint8_t wait) {
Mitchell Pomery's avatar
Mitchell Pomery committed
294
  for (int j=0; j<10; j++) { // do 10 cycles of chasing
Mitchell Pomery's avatar
Mitchell Pomery committed
295 296
    for (int q=0; q < 3; q++) {
      for (int i=0; i < strip.numPixels(); i=i+3) {
Mitchell Pomery's avatar
Mitchell Pomery committed
297
        strip.setPixelColor(i+q, c); // turn every third pixel on
Mitchell Pomery's avatar
Mitchell Pomery committed
298 299 300 301 302 303
      }
      strip.show();
     
      delay(wait);
     
      for (int i=0; i < strip.numPixels(); i=i+3) {
Mitchell Pomery's avatar
Mitchell Pomery committed
304
        strip.setPixelColor(i+q, 0); // turn every third pixel off
Mitchell Pomery's avatar
Mitchell Pomery committed
305 306 307 308 309
      }
    }
  }
}

Mitchell Pomery's avatar
Mitchell Pomery committed
310
// Theatre-style crawling lights with rainbow effect
Mitchell Pomery's avatar
Mitchell Pomery committed
311
void theaterChaseRainbow(uint8_t wait) {
Mitchell Pomery's avatar
Mitchell Pomery committed
312
  for (int j=0; j < 256; j++) { // cycle all 256 colors in the wheel
Mitchell Pomery's avatar
Mitchell Pomery committed
313 314
    for (int q=0; q < 3; q++) {
        for (int i=0; i < strip.numPixels(); i=i+3) {
Mitchell Pomery's avatar
Mitchell Pomery committed
315 316
          // turn every third pixel on
          strip.setPixelColor(i+q, Wheel( (i+j) % 255));
Mitchell Pomery's avatar
Mitchell Pomery committed
317 318 319 320 321 322
        }
        strip.show();
       
        delay(wait);
       
        for (int i=0; i < strip.numPixels(); i=i+3) {
Mitchell Pomery's avatar
Mitchell Pomery committed
323
          strip.setPixelColor(i+q, 0); // turn every third pixel off
Mitchell Pomery's avatar
Mitchell Pomery committed
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
        }
    }
  }
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  if(WheelPos < 85) {
   return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if(WheelPos < 170) {
   WheelPos -= 85;
   return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
   WheelPos -= 170;
   return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

Mitchell Pomery's avatar
Mitchell Pomery committed
343 344
// =============================== MAIN PROGRAM ===============================

Mitchell Pomery's avatar
Mitchell Pomery committed
345
void setup() {
Mitchell Pomery's avatar
Mitchell Pomery committed
346
  // Start Ethernet
Mitchell Pomery's avatar
Mitchell Pomery committed
347
  Ethernet.begin(mac, ip);
Mitchell Pomery's avatar
Mitchell Pomery committed
348
  // Set up webpages
Mitchell Pomery's avatar
Mitchell Pomery committed
349 350 351 352
  webserver.setDefaultCommand(&webSetSequence);
  webserver.addCommand("custom", &webSetSequence);
  webserver.addCommand("individual", &webSetLED);
  webserver.addCommand("brightness", &webSetBrightness);
Mitchell Pomery's avatar
Mitchell Pomery committed
353
  // Start Webserver
Mitchell Pomery's avatar
Mitchell Pomery committed
354
  webserver.begin();
Mitchell Pomery's avatar
Mitchell Pomery committed
355
  // Turn our lights on
Mitchell Pomery's avatar
Mitchell Pomery committed
356 357 358 359 360 361 362 363
  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
364
  strip.setBrightness(128);
Mitchell Pomery's avatar
Mitchell Pomery committed
365 366 367 368 369 370 371 372 373 374 375
  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
376 377
  switch (lightOption) {
    case 0: // Don't change the lights at all
Mitchell Pomery's avatar
Mitchell Pomery committed
378
      break;
Mitchell Pomery's avatar
Mitchell Pomery committed
379
    case 1: // Wipe the LED's to Red
Mitchell Pomery's avatar
Mitchell Pomery committed
380 381 382
      colorWipe(strip.Color(255, 0, 0), 50); // Red
      break;
    default:
Mitchell Pomery's avatar
Mitchell Pomery committed
383
      lightOption = 1;
Mitchell Pomery's avatar
Mitchell Pomery committed
384
      break;
Mitchell Pomery's avatar
Mitchell Pomery committed
385
  }
Mitchell Pomery's avatar
Mitchell Pomery committed
386
  // Show our lights
Mitchell Pomery's avatar
Mitchell Pomery committed
387 388
  showArray();
}