Processing Door Sign

Teensy and Processing code after the video.

So this was my portion of a prototype 'miniature' RFID automated store room.  The prototype was designed to take the functionality of the full-sized CribMaster Accuport, strip the mats out of the process, and replace them with buttons in order to allow the contraption to operate with a smaller footprint.  This also meant that we really needed to make it so only one person was in the cage at a time.  What better way than a colorful sign that asks people to wait their turn?

The door sign runs on a tiny Rapsberry-Pi-like SOC, the Asus Tinkerboard, chosen for its beefier cpu power over that of a regular Raspberry Pi.  To transmit the 'state' of the RFID machine to the Tinkerboard, I programmed a Teensy 3.2 microcontroller to act as an HID device in order to receive signals from a relay and then send key presses to the Tinkerboard to manipulate the states of the door sign.

I had a lot of fun diving into Processing, though I really had to strip back my ambitions for the project due to the limits of the SOC running things.  Having the ability to import SVG files to manipulate was exciting, but things slow way down when you start animating hundreds of vertices.  However, simple shapes can also be a good time.

0:00
/
Processing Door Sign in action.

Teensy 3.2 Code:

/* 
  Based on the Buttons to USB Keyboard Example
*/

#include <Bounce.h>

Bounce button1 = Bounce(4, 10);  
Bounce button2 = Bounce(11, 10);  

void setup() {
  pinMode(4, INPUT_PULLDOWN);  
  pinMode(11, INPUT_PULLDOWN);
}

void loop() {

  button1.update();
  button2.update();

  if (button1.risingEdge()) {
    Keyboard.println("o");
  }
  if (button2.risingEdge()) {
    Keyboard.println("c");
  }
}

Processing Code:

//mcadoorsign_release_v1

DoorSignController ds;


void setup() {
  size(1280,720,JAVA2D);
  noCursor();
  ds = new DoorSignController();
}

void draw() {
  ds.loopDeLoop();
}

void keyPressed() { 
  ds.currentKey = key;
    
  if(ds.currentKey == ds.lastKey) {
    ds.counter++;
  } else {
    ds.counter = 0;
  }
    
  if(ds.counter == 0) {
    if ((key == 'o') || (key == 'O')) {
    //Matt's relay has sent the available signal
      ds.state = 1;
    }
      
    if ((key == 'c') || (key == 'C')) {
    //Matt's relay has sent the unavailable signal
      ds.state = 3;
    }
      
    ds.lastKey = key;
      
    if(ds.state != ds.lastState) {
      ds.toUpdate = true;
      ds.lastState = ds.state;
    } else {
      ds.toUpdate = false;
    }
  }
}
mcadoorsign_release_v1.pde
class AnimationTimer {
  
  // class variables
  float start, runtime = 0;
  
  //constructor
  AnimationTimer() {
    start = millis();
  }
  
  //methods
  void update() {
    runtime = millis() - start;
  }
  
  float getRuntime() {
    return runtime;    
  }
  
  void setStart() {
    start = millis();
  }
  
  float getStart() {
    return start;
  }
}
AnimationTimer.pde
class BackgroundController_new {
  int counter;
  int state = 0; 
  int mainAlpha = 255;
  int x,y = 0;
  int cols = 20;
  int rows = 11;
  int size;
  color green = #207528;
  color red = #530000;  
  color backgroundColor;
  int wipingCounter;
  int waitingCounter;
  boolean wiping,holding;
  int k = 0;
  int lastK = 0;
  ColorSquare[][] grid;
  
  //constructor
  BackgroundController_new(int[][] green, int[][] red, int[][][] alt) {
    backgroundColor = color(0,0,0);
    holding = true;
    wiping = false;
    wipingCounter = 1;
    waitingCounter = 1;
    size = (int)sqrt(((height/width)*width/height)*cols);
    grid = new ColorSquare[cols][rows];
    
    for(int i = 0; i < cols; i++) {
      for(int j = 0; j < rows; j++) {
        int x = (int)(i*width/(cols*1.0));
        int y = (int)(j*height/(rows*1.0));
        grid[i][j] = new ColorSquare(55,x+4,y+4,0,green,red,alt);
      }
    }
  }
  
  //methods
  void update() {
    drawOnCanvas();
  }

  void drawOnCanvas() {
  
    if(state == 0) { // holding in green
      holding = true;
      wiping = false;
      drawHolding();
    }
    
    if(state == 1) { // holding in red
      holding = true;
      wiping = false;
      drawHolding();
    }
    
    if(state == 2) { // wiping to red
      holding = false;
      wiping = true;
      drawWipingToRed();
    }
    
    if(state == 3) { // wiping to green
      holding = false;
      wiping = true;
      drawWipingToGreen();
    }
    
    if(state == 4) { // wiping to alt color
      holding = false;
      wiping = true;
      drawWipingToAlt();
    }
    
    if(state == 5) { // holding alt
      holding = true;
      wiping = false;
      drawHolding();
    }
  }
  
  void drawHolding() {
    for(int i = 0; i < cols; i++) {
      for(int j = 0; j < rows; j++) {
        grid[i][j].holding();
        fill(grid[i][j].C1,grid[i][j].C2,grid[i][j].C3);
        rect(grid[i][j].xPos,grid[i][j].yPos,grid[i][j].size,grid[i][j].size);
      }
    }
  }
  
  void drawWipingToRed() {
    for(int i = 0; i < cols; i++) {
      for(int j = 0; j < rows; j++) {
        grid[i][j].becomeRed();
      }
    }
    state = 2;
    drawHolding();
  }
  
  void drawWipingToGreen() {
    for(int i = 0; i < cols; i++) {
      for(int j = 0; j < rows; j++) {
        grid[i][j].becomeGreen();
      }
    }
    state = 0;
    drawHolding();
  }
  
  void drawWipingToAlt() {
    for(int i = 0; i < cols; i++) {
      for(int j = 0; j < rows; j++) {
        grid[i][j].becomeAlt(k);
      }
    }
    state = 5;
    drawHolding();
  }
  
  int makeRandomIndex() {
    k = (int)random(0,grid[0][0].alts.length);
    if(k == lastK) {
      makeRandomIndex();
    } else {
      lastK = k;
    }    
    return k;  
  }
}
BackgroundController.pde
class ColorSquare {
  
  int size;
  int xPos;
  int yPos;
  int C1;
  int C2;
  int C3;
  int newC1;
  int newC2;
  int newC3;
  int[][] greens;
  int[][] reds;
  int[][][] alts;
  int last;
  int state = 0;
  int type; //0 is a greeney, 1 is a reddy
  boolean start,fading,changing;
  int greenCounter;
  int redCounter;
  int fadeCounter;
  int fadeSteps;
  int c1FadeAmt = 0;
  int c2FadeAmt = 0;
  int c3FadeAmt = 0;
  int clrNmbr;
  
  //constructor
  ColorSquare(int sz, int x, int y, int t, int[][] gr, int[][] rd, int[][][] alt) {
    size = sz;
    xPos = x;
    yPos = y;
    type = t;
    greens = gr;
    reds = rd;
    alts = alt;
    fadeSteps = (int)random(45,75);
    fadeCounter = 0;
    start = true;
    fading = false;
    changing = true;
    last = (int)random(0,2);
    
    if(type == 0) {
      pickRandomGreen();
      start = false;
      pickRandomGreen();    
    }
    
    if(type == 1) {
      pickRandomRed();
      start = false;
      pickRandomRed();
    }
    
    if(type == 2) {
      pickRandomAlt();
      start = false;
      pickRandomAlt();
    }
  }
  
  //methods
  void pickRandomGreen() {
    int i = (int)random(0,greens.length);
    if(i != last) {
      if(start) {
        C1 = greens[i][0];
        C2 = greens[i][1];
        C3 = greens[i][2];
      } else {
        newC1 = greens[i][0];
        newC2 = greens[i][1];
        newC3 = greens[i][2];
      }
      last = i;
    } else {
      pickRandomGreen();
    }
  }
  
  void pickRandomRed() {
    int i = (int)random(0,reds.length);
    if(i != last) {
      if(start) {
        C1 = reds[i][0];
        C2 = reds[i][1];
        C3 = reds[i][2];
      } else {
        newC1 = reds[i][0];
        newC2 = reds[i][1];
        newC3 = reds[i][2];
      }
      last = i;
    } else {
      pickRandomRed();
    }
  }
  
  void pickRandomAlt() {
    //int i = (int)random(0,alts.length);
    int j = (int)random(0,alts[clrNmbr].length);
    if(j != last) {
      if(start) {
        C1 = alts[clrNmbr][j][0];
        C2 = alts[clrNmbr][j][1];
        C3 = alts[clrNmbr][j][2];
      } else {
        newC1 = alts[clrNmbr][j][0];
        newC2 = alts[clrNmbr][j][1];
        newC3 = alts[clrNmbr][j][2];
      }
      last = clrNmbr;
    } else {
      pickRandomAlt();
    }
  }
  
  //this is the main loop for the square
  void drawSquare() {
    if(state == 0) {
      holding();
    }
    
    if(state == 1) {
      becomeGreen();
    }
    
    if(state == 2) {
      becomeRed();
    }
    
    if(state == 3) {
      becomeAlt((int)random(0,alts.length - 1));
    }
  }
  
  void holding() {
    if(changing) {
      //get new random color in set
      if(type == 0) {
        pickRandomGreen();
      }
      if(type == 1) {
        pickRandomRed();
      }
      if(type == 2) {
        pickRandomAlt();
      }
      changing = false;
      fading = true;
      fadeSteps = (int)random(45,75);
      holding();
    }
    
    if(fading) {
      C1 = (int)lerp(C1,newC1,0.07);
      C2 = (int)lerp(C2,newC2,0.07);
      C3 = (int)lerp(C3,newC3,0.07);
      
      fadeCounter+=1;
      if(fadeCounter == fadeSteps) {
        fading = false;
        changing = true;
        fadeCounter = 1;
      }
    }
  }
  
  int fadeColor(int in, int amt) {
    return in + amt;
  }
  
  void becomeGreen() {
    type = 0;
  }
  
  void becomeRed() {
    type = 1;
  }
  
  void becomeAlt(int randomClr) {
    clrNmbr = randomClr;
    type = 2;
  }  
}
ColorSquare.pde
class Logo {
  boolean drawFadeIn, drawHold, drawFadeOut, off = false;
  PShape mcaLogo, mca, ind;
  color rectColor = color(0,0,0);
  DoorSign parent;
  PShape grp;
  PShape[] theLetters;
  PShape theMessageShape;
  int alpha = 255;
  float ratio = 0.9;
  int rectAlpha = 0;
  int finalRectAlpha = 229;
  int offCounter;
  int fadingCounter;
  int x,y,targetX,targetY;
  boolean moveUp, moveDown, hold;
  float lerpAmount = 0.06;
  float fadeLerpAmount = 0.2;

  //constructor
  Logo() {
    off = true;
    fadingCounter = 0;
    rectAlpha = (int)(alpha * ratio);
    mcaLogo = loadShape("mcalogo.svg");
    mca = mcaLogo.getChild("MCA");
    ind = mcaLogo.getChild("INDUSTRIAL");
    mca.disableStyle();
    ind.disableStyle();
    x = 0;
    y = 721;
    targetX =0;
    targetY = 389+65;
    hold = true;
    moveUp = false;
    moveDown = false;
  }
  
  //methods
  void draw() {
  
    if(drawFadeIn) {
      fadeIn();
    }
    
    if(drawHold) {
      messageHold();
    }
    
    if(drawFadeOut) {
      fadeOut();
    }  
    
    if(off) {
      off();
    }
  }
  
  void fadeIn() {
    if(fadingCounter == 0) {
      alpha = 0;
      rectAlpha = 0;
    }
    updateFadeCounters();
    float b;
    if(alpha < 255) {
      stroke(0,0,0,alpha);
      strokeWeight(4);
      fill(rectColor,rectAlpha);
      rect(0,y,width,200);
      noStroke();
      fill(255,255,255,alpha);
      shape(mca,50,y);
      fill(235,34,40,alpha);
      shape(ind,50,y);
      b = (int)lerp(alpha,255,fadeLerpAmount);
      alpha = (int)b;
      if(alpha >= 250) {
        alpha = 255;
      }
      rectAlpha = (int)(alpha * ratio);
      if(rectAlpha > finalRectAlpha) {
        rectAlpha = finalRectAlpha;
      }
    } else {
      stroke(0,0,0,alpha);
      strokeWeight(4);
      fill(rectColor,rectAlpha);
      rect(0,y,width,200);
      noStroke();
      fill(255,255,255,alpha);
      shape(mca,50,y);
      fill(235,34,40,alpha);
      shape(ind,50,y);   
    }
    
    if(alpha == 255) {
      off = false;
      drawFadeIn = false;
      drawHold = true;
    }
  }
  
  void messageHold() {
    fadingCounter = 0;
    alpha = 255;
    rectAlpha = (int)(alpha * ratio);
    off = false;
    drawFadeIn = false;
    drawFadeOut = false;
    stroke(0,0,0,alpha);
    strokeWeight(4);
    fill(rectColor,rectAlpha);
    rect(0,y,width,200);
    noStroke();
    fill(255,255,255,alpha);
    shape(mca,50,y);
    fill(235,34,40,alpha);
    shape(ind,50,y);
  }
  
  void fadeOut() {
    if(fadingCounter == 0) {
      alpha = 255;
      rectAlpha = (int)(alpha * ratio);
    }
    updateFadeCounters();
    float b;    
    if(alpha > 0) {
      stroke(0,0,0,alpha);
      strokeWeight(4);
      fill(rectColor,rectAlpha);
      rect(0,y,width,200);
      noStroke();
      fill(255,255,255,alpha);
      shape(mca,50,y);
      fill(235,34,40,alpha);
      shape(ind,50,y);
      b = (int)lerp(alpha,0,fadeLerpAmount);
      alpha = (int)b-1;
      rectAlpha = (int)(alpha * ratio);
    } else {
      alpha = 0;
      stroke(0,0,0,alpha);
      strokeWeight(4);
      fill(rectColor,rectAlpha);
      rect(0,y,width,200);
      noStroke();
      fill(255,255,255,alpha);
      shape(mca,50,y);
      fill(235,34,40,alpha);
      shape(ind,50,y);
    }
    
    if(alpha == 0) {
      drawFadeOut = false;
      drawHold = false;
      off = true;
    }
  }
  
  void moveUp() {
    float b;
    if(y > targetY) {
      b = (int)lerp(y,targetY,lerpAmount);
      y = (int)b-1;
    } else {
      moveUp = false;
      hold = true;
      y = targetY;
    }
  }
  
  void moveDown() {
    float b;
    if(y < targetY) {
      b = (int)lerp(y,targetY,lerpAmount);
      y = (int)b+1;
    } else {
      moveDown = false;
      drawHold = false;
      hold = false;
      off = true;
      y = targetY;
    }
  }
  
  
  void updateFadeCounters() {
    fadingCounter+=1;
    
    if(fadingCounter > 5) {
      fadingCounter = 1;
    }
  } 
}
Logo.pde
class Message {
  boolean drawFadeIn, drawHold, drawFadeOut, off = false;
  DoorSign parent;
  PShape grp;
  PShape[] theLetters;
  PShape theMessageShape;
  int alpha;
  int offCounter;
  int x,y,targetX,targetY;
  boolean moveUp, moveDown, hold;
  float lerpAmount = 0.1;
  float fadeLerpAmount = 0.2;
  color rectColor = color(28,28,28);
  int rectSize = 328;
  float ratio = 0.6;
  int rectAlpha;
  int finalRectAlpha = 140;
  int fadingCounter = 0;
  
  //constructor
  Message(int type, DoorSign theParent) {
    
    parent = theParent;
    if(type == 0) {
      grp = loadShape("available.svg");
      drawHold = true;
      drawFadeIn = false;
      drawFadeOut = false;
      off = false;
      alpha = 255;
      rectAlpha = (int)(alpha * ratio);
    }
    
    if(type == 1) {
      grp = loadShape("inuse.svg");
      drawHold = false;
      drawFadeIn = false;
      drawFadeOut = false;
      off = true;
      alpha = 0;
      rectAlpha = 0;
    }
    grp.disableStyle();
    x = 0;
    y = 0;
    targetX =0;
    targetY = -360;
    hold = true;
    moveUp = false;
    moveDown = false;
  }
  
  void draw() {
    if(drawFadeIn) {
      fadeIn();
    }
    
    if(drawHold) {
      messageHold();
    }
    
    if(drawFadeOut) {
      fadeOut();
    }  
    
    if(off) {
      off();
    }
  }
  
  void fadeIn() {
    if(fadingCounter == 0) {
      alpha = 0;
      rectAlpha = 0;
    }
    updateFadeCounters();
    if(alpha < 255) {
      stroke(0,0,0,alpha);
      strokeWeight(4);
      fill(rectColor,rectAlpha);
      rect(0,y+193,width,rectSize);
      noStroke();
      fill(color(255,255,255,alpha));
      shape(grp,x,y);
      alpha = (int)lerp(alpha,255,fadeLerpAmount);
      if(alpha >= 250) {
        alpha = 255;
      }
      rectAlpha = (int)(alpha * ratio);
      if(rectAlpha > finalRectAlpha) {
        rectAlpha = finalRectAlpha;
      }
    } else {
      stroke(0,0,0,alpha);
      strokeWeight(4);
      fill(rectColor,rectAlpha);
      rect(0,y+193,width,rectSize);
      noStroke();
      fill(color(255,255,255,alpha));
      shape(grp,x,y);        
    }
    
    if(alpha == 255 && parent.timeWaited > parent.waitTime) {
      off = false;
      drawFadeIn = false;
      drawHold = true;
    }
  }
  
  void messageHold() {
    fadingCounter = 0;
    off = false;
    drawFadeIn = false;
    drawFadeOut = false;
    stroke(0,0,0,alpha);
    strokeWeight(4);
    fill(rectColor,rectAlpha);
    rect(0,y+193,width,rectSize);
    noStroke();
    fill(color(255,255,255));
    shape(grp,x,y);
  }
  
  void fadeOut() {
    
    if(fadingCounter == 0) {
      alpha = 255;
      rectAlpha = (int)(alpha * ratio);
    }
    updateFadeCounters();
    
    if(alpha > 0) {
      stroke(0,0,0,alpha);
      strokeWeight(4);
      fill(rectColor,rectAlpha);
      rect(0,y+193,width,rectSize);
      noStroke();
      fill(color(255,255,255,alpha));
      shape(grp,x,y);
      alpha = (int)lerp(alpha,0,fadeLerpAmount);
      rectAlpha = (int)(alpha * ratio);
    } else {
      alpha = 0;
      rectAlpha = 0;
      stroke(0,0,0,alpha);
      strokeWeight(4);
      fill(rectColor,rectAlpha);
      rect(0,y+193,width,rectSize);
      noStroke();
      fill(color(255,255,255,alpha));
      shape(grp,x,y);
    }

    if(alpha == 0) {
      drawFadeOut = false;
      drawHold = false;
      off = true;
    }

  }
  
  void moveUp() {
    float b;
    if(y > targetY) {
      b = (int)lerp(y,targetY,lerpAmount);
      y = (int)b-1;
    } else {
      moveUp = false;
      hold = true;
      y = targetY;
    }
  }
  
  void moveDown() {
    if(y < targetY) {
      y = (int)lerp(y,targetY,lerpAmount);
    } else {
      moveDown = false;
      hold = true;
      y = targetY;
    }
  }

  void updateFadeCounters() {
    fadingCounter+=1;
    
    if(fadingCounter > 5) {
      fadingCounter = 1;
    }
  }
}
Message.pde
class DoorSign {
  Logo logo;
  Message ava;
  Message inUse;
  BackgroundController_new aBack;
  AllTheColors someColors;
  color theColor, theBackgroundColor;
  int counter = 0;
  int transformCounter = 0;
  int availableCounter = 0;
  int unavailableCounter = 0;
  int fadingCounter = 0;
  int runCounter = 0;
  
  // Door sign operation variables
  boolean available, becomingAvailable, unavailable, becomingUnavailable,transformAvailable,recheck;
  AnimationTimer waitTimer,displayTimer;
  float timeWaited = 0;
  float waitTime = 1000;
  float displayTime = 20000;
  boolean availableState,unavailableState;
  DoorSignController parent;
  int randomIndex = 0;

  //constructor
  DoorSign() {
    someColors = new AllTheColors();
    logo = new Logo();
    ava = new Message(0,this);
    inUse = new Message(1,this);
    aBack = new BackgroundController_new(someColors.greens,someColors.reds,someColors.alts);
    waitTimer = new AnimationTimer();
    waitTimer.setStart();
    displayTimer = new AnimationTimer();
    displayTimer.setStart();
    available = true;
    becomingAvailable = false;
    unavailable = false;
    becomingUnavailable = false;
	
    inUse.alpha = 0;
    inUse.off = true;
    inUse.drawHold = false;
    inUse.drawFadeIn = false;
    inUse.drawFadeOut = false;
 
    ava.alpha = 255;
    ava.drawHold = true;
    ava.off = false;
    ava.drawFadeIn = false;
    ava.drawFadeOut = false;
    
    aBack.state = 1;
    availableState = false;
    unavailableState = false;
    
    logo.off = true;
  }
  
  //methods
  void draw() {
    noStroke();
    aBack.update();
    waitTimer.update();
    displayTimer.update();
    
    //if available, check the displayTimer
    if(available) {
    
	  // if the display time limit has been reached, switch to opposite states
      if(displayTimer.getRuntime() > displayTime) { 
        availableState = !availableState;
        unavailableState = !unavailableState;
        
        if(availableState) {
          ava.moveUp = true;
          ava.moveDown = false;
          ava.hold = false;
          ava.targetY = -130; // to move up
          logo.off = false;
          logo.moveUp = true;
          logo.moveDown = false;
          logo.hold = false;
          logo.drawHold = true;
          logo.targetY = 389+65;
          aBack.state = 4;
          randomIndex = aBack.makeRandomIndex();
        }
        
        if(!availableState) {
          ava.moveUp = false;
          ava.moveDown = true;
          ava.hold = false;
          ava.targetY = 0; // back down
          logo.moveUp = false;
          logo.moveDown = true;
          logo.hold = false;
          logo.targetY = 721;
          aBack.state = 3;
        }

        transformAvailable = true;
        available = false;
        runCounter+=1;
        if(runCounter < 10) {
          runCounter = 1;
        }
      }
    } //end of available displayTimer check
    
    // if in the normal state
    if(availableState) { //normal state
    
      if(available) { 
        drawAvailable(); // draw the regular availabe
      }

      if(becomingAvailable) {
        drawBecomingAvailableAlt(); // draw the regular becoming available
      }
      
      if(transformAvailable) {
        drawTransformAvailable();
      }
    }
    
    // if in the alternate state
    if(!availableState) { //alternate state
      if(available) {
	    // draw alternate available
        drawAvailable();
      }
      
      if(becomingAvailable) {
	    // draw alternate becoming available
        drawBecomingAvailable();
      }
      
      if(transformAvailable) {
        drawTransformAvailableAlt(); // draw the alternate transform back to normal state available
      }
    }
   
    // if in the normal state
    if(unavailableState) { // normal state
  
      if(unavailable) {
        drawUnavailable(); // draw unavailable
      }
  
      if(becomingUnavailable) {
        drawBecomingUnavailableAlt(); // draw normal becoming unavailalbe
      } 
    }
    
    // if in the alternate state
    if(!unavailableState) { //alternate state
    
      if(unavailable) {
        drawUnavailable();
      }
          
      if(becomingUnavailable) {
	    // draw the alternate becoming unavailable state in 
		// which both the available and McAuliffe's logo fade out.
        drawBecomingUnavailableAlt(); 
      }
    }
  }
  
//=====  DRAW METHODS BASED ON STATE OF THE DOOR SIGN ====
  void drawBecomingUnavailableAlt() {
    if(fadingCounter == 0) {
      inUse.alpha = 0;
      ava.alpha = 255;
      logo.alpha = 255;
    }
    if(!ava.off) {
      ava.drawHold = false;
      ava.drawFadeOut = true;
      logo.drawHold = false;
      logo.drawFadeOut = true;
      logo.draw();
      ava.draw();
      updateFadeCounters();
    } else if(ava.off && !inUse.drawHold) {
      timeWaited = waitTimer.getRuntime();
      if(timeWaited > waitTime) {
        inUse.off = false;
        inUse.drawFadeIn = true;
        inUse.draw();
        updateFadeCounters();
      }
    } else if(ava.off && logo.off && inUse.drawHold) {
      becomingUnavailable = false;
      unavailable = true;
      fadingCounter = 0;
      inUse.draw();
      randomIndex = aBack.makeRandomIndex();
      logo.rectColor = color(aBack.grid[0][0].alts[aBack.k][3][0],aBack.grid[0][0].alts[aBack.k][3][1],aBack.grid[0][0].alts[aBack.k][3][2]);
    }
  }

  void drawBecomingAvailableAlt() {
    color(aBack.grid[0][0].alts[aBack.k][3][0],aBack.grid[0][0].alts[aBack.k][3][1],aBack.grid[0][0].alts[aBack.k][3][2]);
    if(fadingCounter == 0) {
      ava.alpha = 0;
      logo.alpha = 0;
      logo.rectAlpha = 0;
      inUse.alpha = 255;
    }
    
    fadingCounter+=1;
    
    if(fadingCounter > 5) {
      fadingCounter = 1;
    }
    
    if(!inUse.off) {
      inUse.drawHold = false;
      inUse.drawFadeOut = true;
      inUse.draw();
      updateFadeCounters();
    } else if(inUse.off && !ava.drawHold) {
      timeWaited = waitTimer.getRuntime();
      if(timeWaited > waitTime) {
        ava.off = false;
        ava.drawFadeIn = true;
        logo.off = false;
        logo.drawFadeIn = true;
        logo.draw();
        ava.draw();
        updateFadeCounters();
      }
    } else if(inUse.off && ava.drawHold && logo.drawHold) {
      becomingAvailable = false;
      available = true;
      logo.draw();
      ava.draw();
    }
  }
  
  // this method, we are starting normal available, moving up the 
  // available message, and bringing in the mcauliffe's logo
  void drawTransformAvailable() {  
    if(transformCounter == 0) {
      randomIndex = aBack.makeRandomIndex();
      logo.rectColor = color(aBack.grid[0][0].alts[aBack.k][3][0],aBack.grid[0][0].alts[aBack.k][3][1],aBack.grid[0][0].alts[aBack.k][3][2]);
    }
    transformCounter+=1;
    if(transformCounter > 10) {
      transformCounter = 1;
    }
    
	// make sure that when the ava y coordinate is at the  
	// targetY to set the moveUp to false and the hold to true
    if(ava.moveUp) {
      ava.moveUp();
    }
    
    if(logo.moveUp) {
      logo.moveUp();
    }

    ava.draw();
    logo.draw();

    if(ava.hold && logo.hold) {
      transformAvailable = false;
      available = true;
      displayTimer.setStart();
      transformCounter = 0;
    }
  } // END OF DRAWTRANSFORMAVAILABLE()
  
  // this method changes the avilable message from the alternate 
  // state back to the normal state available message without the logo.
  void drawTransformAvailableAlt() {
    if(ava.moveDown) {
      ava.moveDown();
    }
  
    if(logo.moveDown) {
      logo.moveDown();
    }

    ava.draw();
    logo.draw();
    
    if(ava.hold && logo.off) {
      transformAvailable = false;
      available = true;
      displayTimer.setStart();
    }
  }
  
  void drawAvailable() {
    fadingCounter = 0;
    ava.drawHold = true;
    inUse.off = true;
    ava.draw(); 
    if(!logo.off) {
      logo.draw();
    }
  }
  
  void drawAvailableAlt() {
    fadingCounter = 0;
    ava.drawHold = true;
    inUse.off = true;
    ava.draw(); 
    logo.draw();
  }
  
  void drawBecomingAvailable() {
    if(fadingCounter == 0) {
      ava.alpha = 0;
      inUse.alpha = 255;
    }
    if(!inUse.off) {
      inUse.drawHold = false;
      inUse.drawFadeOut = true;
      inUse.draw();
      updateFadeCounters();
    } else if(inUse.off && !ava.drawHold) {
      timeWaited = waitTimer.getRuntime();
      if(timeWaited > waitTime) {
        ava.off = false;
        ava.drawFadeIn = true;
        ava.draw();
        updateFadeCounters();
      }
    } else if(inUse.off && ava.drawHold) {
      becomingAvailable = false;
      available = true;
      ava.draw();
    }
    
    fadingCounter+=1;
    
    if(fadingCounter > 5) {
      fadingCounter = 1;
    }
  }
  
  void drawUnavailable() {
    fadingCounter = 0;
    inUse.drawHold = true;
    ava.off = true;
    inUse.draw(); 
  }
  
  void drawBecomingUnavailable() {
    if(fadingCounter == 0) {
      inUse.alpha = 0;
      ava.alpha = 255;
    }
    if(!ava.off) {
      ava.drawHold = false;
      ava.drawFadeOut = true;
      ava.draw();
      updateFadeCounters();
    } else if(ava.off && !inUse.drawHold) {
      timeWaited = waitTimer.getRuntime();
      if(timeWaited > waitTime) {
        inUse.off = false;
        inUse.drawFadeIn = true;
        inUse.draw();
        updateFadeCounters();
      }
    } else if(ava.off && inUse.drawHold) {
      becomingUnavailable = false;
      unavailable = true;
      randomIndex = aBack.makeRandomIndex();
      logo.rectColor = color(aBack.grid[0][0].alts[aBack.k][3][0],aBack.grid[0][0].alts[aBack.k][3][1],aBack.grid[0][0].alts[aBack.k][3][2]);
      fadingCounter = 0;
      inUse.draw();
    }
  }
  
  void updateFadeCounters() {
    fadingCounter+=1;
    
    if(fadingCounter > 5) {
      fadingCounter = 1;
    }
  }
  
  void update() {
    waitTimer.update();    
  }
  
  void makeBecomingAvailable() {
    becomingAvailable = true;
    becomingUnavailable = false;
    unavailable = false;
    available = false;
    if(availableState) {
      aBack.state = 4;
      logo.rectColor = color(aBack.grid[0][0].alts[aBack.k][3][0],aBack.grid[0][0].alts[aBack.k][3][1],aBack.grid[0][0].alts[aBack.k][3][2]);
    } else {
      aBack.state = 3;
    }
    
    waitTimer.setStart();
    displayTimer.setStart();
  }
  
  void makeBecomingUnavailable() {
    becomingAvailable = false; 
    available = false;
    becomingUnavailable = true;
    unavailable = false;
    aBack.state = 2;
    waitTimer.setStart();
    displayTimer.setStart();
  } 
}
DoorSign.pde
class DoorSignController {
  DoorSign doorSign;
  char lastKey;
  char currentKey;
  int counter;
  int state; //0 available, 1 becomingAvailable, 2 unavailable, 3 becomingUnavailable
  int lastState;//
  boolean recheck;
  boolean toUpdate;
  boolean updateColors;
  
  //constructor
  DoorSignController() {
    recheck = false;
    toUpdate = false;
    updateColors = false;
    doorSign = new DoorSign();
    lastKey = 'o';
    counter = 0;  
    state = 0;
    lastState = 0;
  }
  
  //methods
  void loopDeLoop() {
    background(doorSign.aBack.backgroundColor);
    checkState(); // check for new button presses?
    doorSign.update();
    doorSign.draw();
    //println(frameRate);
  }
  
  void checkState() {
    if(toUpdate) {
      if(doorSign.available || doorSign.unavailable) {
        if(state == 1) {
          doorSign.makeBecomingAvailable();
          toUpdate = false;
          state = 0;
        }
        
        if(state == 3) {
          doorSign.makeBecomingUnavailable();
          toUpdate = false;
          state = 2;
        }
      }
    }
  }
  
  void updateColors() {
    doorSign.randomIndex = doorSign.aBack.makeRandomIndex();
    doorSign.logo.rectColor = color(doorSign.aBack.grid[0][0].alts[doorSign.aBack.k][3][0],doorSign.aBack.grid[0][0].alts[doorSign.aBack.k][3][1],doorSign.aBack.grid[0][0].alts[doorSign.aBack.k][3][2]);
    updateColors = false;
  }
}
DoorSignController.pde
class AllTheColors {
  int[][] greens;
  int[][] reds;
  int[][][] alts;
  //midGreen 
  int mgC1 = 78;
  int mgC2 = 130;
  int mgC3 = 0;
  //midLightGreen
  int mlgC1 = 115;
  int mlgC2 = 173;
  int mlgC3 = 27;
  //darkGreen
  int dgC1 = 66;
  int dgC2 = 102;
  int dgC3 = 13;
  //lightGreen
  int lgC1 = 155;
  int lgC2 = 255;
  int lgC3 = 0;
  //midRed 
  int mrC1 = 174;
  int mrC2 = 0;
  int mrC3 = 0;
  //midLightRed
  int mlrC1 = 229;
  int mlrC2 = 0;
  int mlrC3 = 0;
  //darkRed 
  int drC1 = 119;
  int drC2 = 1;
  int drC3 = 1;
  //lightRed 
  int lrC1 = 255;
  int lrC2 = 12;
  int lrC3 = 12;
  //midBlue 
  int mbC1 = 13;
  int mbC2 = 89;
  int mbC3 = 170;
  //midLightBlue
  int mlbC1 = 0;
  int mlbC2 = 115;
  int mlbC3 = 239;
  //darkBlue 
  int dbC1 = 11;
  int dbC2 = 95;
  int dbC3 = 186;
  //lightBlue 
  int lbC1 = 93;
  int lbC2 = 170;
  int lbC3 = 252;
  // light purple
  int lpC1= 239;
  int lpC2= 93;
  int lpC3= 212;
  // mid light purple
  int mlpC1= 237;
  int mlpC2= 64;
  int mlpC3= 205;
  // mid purple
  int mpC1= 160;
  int mpC2= 25;
  int mpC3= 135;
  // dark purple
  int dpC1= 76;
  int dpC2= 0;
  int dpC3= 62;
  // light yellow
  int lyC1= 255;
  int lyC2= 255;
  int lyC3= 73;
  // mid light yellow
  int mlyC1= 247;
  int mlyC2= 247;
  int mlyC3= 2;
  // mid yellow
  int myC1= 216;
  int myC2= 216;
  int myC3= 2;
  // dark yellow
  int dyC1= 200;
  int dyC2= 200;
  int dyC3= 0;
  // light some other color
  int ltC1= 200;
  int ltC2= 200;
  int ltC3= 200;
  // mid light some other color
  int mltC1= 128;
  int mltC2= 128;
  int  mltC3= 128;
  // mid some other color
  int mtC1= 49;
  int mtC2= 49;
  int mtC3= 49;
  // dark some other color
  int dtC1= 0;
  int dtC2= 0;
  int dtC3= 0;
  
  //constructor
  AllTheColors() {
    makeColorArrays();    
  }
  
  //methods
  void makeColorArrays() {
    greens = new int[4][3];
    reds = new int[4][3];
    alts = new int[4][4][3];
    
    makeAlts();
    
    greens[0][0] = lgC1;
    greens[0][1] = lgC2;
    greens[0][2] = lgC3;
    greens[1][0] = mlgC1;
    greens[1][1] = mlgC2;
    greens[1][2] = mlgC3;
    greens[2][0] = mgC1;
    greens[2][1] = mgC2;
    greens[2][2] = mgC3;
    greens[3][0] = dgC1;
    greens[3][1] = dgC2;
    greens[3][2] = dgC3;
    reds[0][0] = lrC1;
    reds[0][1] = lrC2;
    reds[0][2] = lrC3;
    reds[1][0] = mlrC1;
    reds[1][1] = mlrC2;
    reds[1][2] = mlrC3;
    reds[2][0] = mrC1;
    reds[2][1] = mrC2;
    reds[2][2] = mrC3;
    reds[3][0] = drC1;
    reds[3][1] = drC2;
    reds[3][2] = drC3;
  }

  void makeAlts() {
    alts[0][0][0] = lbC1;
    alts[0][0][1] = lbC2;
    alts[0][0][2] = lbC3;
    alts[0][1][0] = mlbC1;
    alts[0][1][1] = mlbC2;
    alts[0][1][2] = mlbC3;
    alts[0][2][0] = mbC1;
    alts[0][2][1] = mbC2;
    alts[0][2][2] = mbC3;
    alts[0][3][0] = dbC1;
    alts[0][3][1] = dbC2;
    alts[0][3][2] = dbC3;
    alts[1][0][0] = lpC1;
    alts[1][0][1] = lpC2;
    alts[1][0][2] = lpC3;
    alts[1][1][0] = mlpC1;
    alts[1][1][1] = mlpC2;
    alts[1][1][2] = mlpC3;
    alts[1][2][0] = mpC1;
    alts[1][2][1] = mpC2;
    alts[1][2][2] = mpC3;
    alts[1][3][0] = dpC1;
    alts[1][3][1] = dpC2;
    alts[1][3][2] = dpC3;
    alts[2][0][0] = lyC1;
    alts[2][0][1] = lyC2;
    alts[2][0][2] = lyC3;
    alts[2][1][0] = mlyC1;
    alts[2][1][1] = mlyC2;
    alts[2][1][2] = mlyC3;
    alts[2][2][0] = myC1;
    alts[2][2][1] = myC2;
    alts[2][2][2] = myC3;
    alts[2][3][0] = dyC1;
    alts[2][3][1] = dyC2;
    alts[2][3][2] = dyC3;
    alts[3][0][0] = ltC1;
    alts[3][0][1] = ltC2;
    alts[3][0][2] = ltC3;
    alts[3][1][0] = mltC1;
    alts[3][1][1] = mltC2;
    alts[3][1][2] = mltC3;
    alts[3][2][0] = mtC1;
    alts[3][2][1] = mtC2;
    alts[3][2][2] = mtC3;
    alts[3][3][0] = dtC1;
    alts[3][3][1] = dtC2;
    alts[3][3][2] = dtC3;
  }
}
AllTheColors.pde

Now that I've gone and looked through all this code again for the first time in a few years, I'm a) realizing that I could probably reformat things to tidy it up a little (sooo many variables for the colors) and b) feeling pretty good I pulled this one off given it was my first foray into Processing.  My door sign has been running 24/7 for about 4 years now without a hitch :D