#include <Adafruit_NeoPixel.h>
#include <Servo.h>
#include <SPI.h>
#include <Ethernet.h>
// PWM pins (3, 5, 6, 9, 10, or 11)
#define FOG_PIN 3
#define SD_CARD_BLOCK 4
#define LIGHT_PIN 5 // Control the light strip
#define ARROW_PIN 9 // Control the servo
#define N 50 // # of lights in the chain
#define FLUX_START 8 // first light in the flux
#define FLUX_END 21 // last light in the flux
#define ELEVATOR_START 26 // first light in the elevator arc
#define ELEVATOR_END 50 // not inclusive (so this is the last index + 1)
#define LIGHTS_PER_FLOOR 3
#define DEG_PER_FLOOR 22 // servo degees per floor
#define DEG_FLOOR_ZERO 180
#define FLUX_DELAY 100
#define FLOOR_DELAY 1000
#define RAINBOW_DELAY 200
#define ARROW_DELAY 1000
#define FOG_DELAY 3000
#define SERVO_DETACH_DELAY 2000 // Need to detach servo to prevent jitter
// Parameter 3 = pixel type flags, add together as needed:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(N, LIGHT_PIN, NEO_RGB + NEO_KHZ800);
byte mac[] = { 0xDE, 0xAD, 0xEE, 0xEF, 0xFE, 0xEF }; //physical mac address
byte ip[] = { 192, 168, 1, 27 }; // arduino server ip in lan
EthernetServer server(80); //arduino server port
// Some predefined color values
uint32_t elevator_off = strip.Color(0, 0, 10);
uint32_t elevator_on = strip.Color(250, 0, 0);
uint32_t flux_back = strip.Color(0, 20, 0);
uint32_t flux_move = strip.Color(120, 120, 120);
uint32_t flux_back_low = strip.Color(10, 0, 10);
uint32_t flux_move_low = strip.Color(0, 20, 0);
uint32_t flux_back_high = strip.Color(0, 70, 0);
uint32_t flux_move_high = strip.Color(250, 250, 250);
// Timers allow the main thread to continue
long floorTimer = 0;
long fluxTimer = 0;
long jitterTimer = 0;
long rainbowTimer = 0;
long crazyArrowTimer = 0;
long fogTimer = 0;
// Array of the index of light that make up the flux C
byte fluxPosition[5][3]={
{8,14,20},
{9,15,19},
{10,13,18},
{11,16,17},
{12,12,12}
};
Servo arrowServo; // create servo object to control a servo
int currentFloor = 0;
int destinationFloor = 0;
int fluxStep = 0;
boolean noJitter = true;
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
// Network start
Ethernet.begin(mac, ip);
server.begin();
debug("Setup complete");
// disable SD card
pinMode(SD_CARD_BLOCK, OUTPUT);
digitalWrite(SD_CARD_BLOCK, HIGH);
pinMode(FOG_PIN, OUTPUT);
digitalWrite(FOG_PIN, HIGH); // fog off
strip.begin();
setAll(strip.Color(0,0,0));
setFloor(1);
setFluxPower(1);
}
void loop() {
checkNetwork();
checkTimers();
delay(40);
}
// Check to see if any of the timers need the next step
// Using these timers help prevent locking of the single thread
void checkTimers() {
if(floorTimer > 0 && floorTimer < millis()) {
floorTimer = 0;
stepFloor();
}
if(fluxTimer > 0 && fluxTimer < millis()) {
fluxTimer = 0;
stepFlux();
}
if(jitterTimer > 0 && jitterTimer < millis()) {
jitterTimer = 0;
arrowServo.detach();
}
if(rainbowTimer > 0 && rainbowTimer < millis()) {
rainbowTimer = 0;
stepRainbow();
}
if(crazyArrowTimer > 0 && crazyArrowTimer < millis()) {
stepArrow();
crazyArrowTimer = millis() + ARROW_DELAY;
}
if(fogTimer > 0 && fogTimer < millis()) {
fogTimer = 0;
digitalWrite(FOG_PIN, HIGH);
}
}
void debug(String s) {
//Serial.println(s);
}
void checkNetwork() {
int from, to;
String readString;
// Create a client connection
EthernetClient client = server.available();
if (client) {
while (client.connected()) {
if (client.available()) {
char c = client.read();
//read char by char HTTP request
if (readString.length() < 100) {
//store characters to string
readString += c;
}
//if this is the end of a single line
if (c == '\n') {
debug(readString);
delay(1);
// The loop ignore all string that are not a get request
if(readString.indexOf("GET") == 0) {
Serial.println(readString);
debug(readString);
from = readString.indexOf("/") + 1;
to = readString.indexOf("/", from);
if((to - from) == 1) { // ignore everything but a single character URL
c = readString.charAt(from);
if(c == 'a') { // 'a' is command for set all
from = to+1;
to = readString.indexOf(",", from);
int red = parseString(readString, from, to);
from = to + 1;
to = readString.indexOf(",", from);
int green = parseString(readString, from, to);
from = to + 1;
to = readString.indexOf(" ", from);
int blue = parseString(readString, from, to);
setAll(strip.Color(red, green, blue));
}
if(c == 'f') { // f = floor
from = to + 1;
to = readString.indexOf(" ", from);
int floor = parseString(readString, from, to);
setFloor(floor);
}
if(c == 'g') { // g = go to floor
from = to + 1;
to = readString.indexOf(" ", from);
destinationFloor = parseString(readString, from, to);
stepFloor();
}
if(c == 'c') { // begin flux capacitor
from = to + 1;
to = readString.indexOf(" ", from);
int level = parseString(readString, from, to);
setFluxPower(level);
stepFlux();
}
if(c == 'C') { // end/stop the flux
fluxTimer = 0;
setFluxColor(strip.Color(0,0,0));
}
if(c == 'r') { // r = crazy rainbow
stepRainbow();
}
if(c == 'R') { // e = end/stop the rainbow
rainbowTimer = 0;
setFloor(currentFloor);
}
if(c == 'z') { // z = fog
fog();
}
if(c == 's') { // Random arrow
stepArrow();
crazyArrowTimer = millis() + ARROW_DELAY;
}
if(c == 'S') { // Stop arrow
crazyArrowTimer = 0;
setFloor(currentFloor);
}
if(c == 'w') { // Go wild
// Flux power to high and turn it on
setFluxPower(2);
stepFlux();
// Crazy arrow
stepArrow();
crazyArrowTimer = millis() + ARROW_DELAY;
// Crazy rainbow
stepRainbow();
}
if(c == 'W') { // end wild
crazyArrowTimer = 0;
rainbowTimer = 0;
setFluxPower(1);
delay(200);
setFloor(currentFloor);
}
}
htmlResponseS(client);
//stopping client
client.stop();
Serial.println("Stopped");
debug("stopped");
}
//clearing string for next read
readString="";
}
}
}
Serial.println("Exit");
}
}
int parseString(String s, int from, int to) {
char carray[6];
s.substring(from, to).toCharArray(carray, to - from + 1);
int i = atoi(carray);
return i;
}
// Full html response
void htmlResponse(EthernetClient client) {
//now output HTML data header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();
client.println("<HTML>");
client.println("<HEAD>");
client.println("<TITLE>Kapers</TITLE>");
client.println("<style>");
client.println("body { font-size: 75pt; text-align: center; }");
client.println("</style>");
client.println("</HEAD>");
client.println("<BODY>");
client.println("<a href=\"/c/\">Start</a> Flux Cap. <a href=\"/C/\">Stop</a><br/>");
client.println("<a href=\"/w/\">Start</a> Wild <a href=\"/W/\">Stop</a><br/>");
client.println("GO ");
for(int i = 1; i <= 8; i++) {
client.print("<a href=\"/g/");
client.print(i);
client.print("\">");
client.print(i);
client.print("</a> ");
}
client.println("<br/>");
client.println("Jump ");
for(int i = 1; i <= 8; i++) {
client.print("<a href=\"/f/");
client.print(i);
client.print("\">");
client.print(i);
client.print("</a> ");
}
client.println("<br/>");
client.println("<a href=\"/z/\">Fog</a><br/>");
client.println("<br/>");
client.println("</BODY>");
client.println("</HTML>");
}
// Shortened response - easier when run from curl
void htmlResponseS(EthernetClient client) {
//now output HTML data header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();
client.println("<HTML><HEAD><BODY>Kapers</BODY></HTML>");
}
// Set all the lights to a single color
void setAll(uint32_t color) {
for(uint16_t i=0; i < N; i++) {
strip.setPixelColor(i, color);
}
strip.show();
}
void setRange(uint32_t color, int from, int to) {
for(uint16_t i=from; i < to; i++) {
strip.setPixelColor(i, color);
}
//strip.show();
}
void fog() {
digitalWrite(FOG_PIN, LOW);
fogTimer = millis() + FOG_DELAY;
}
// -------------------------- Elevator functions ------------------------------
// Jump to a floor
void setFloor(int floor) {
currentFloor = floor;
jitterTimer = millis() + SERVO_DETACH_DELAY;
if(!arrowServo.attached()) {
arrowServo.attach(ARROW_PIN); // attaches the servo on a pin to the servo object
}
arrowServo.write(DEG_FLOOR_ZERO - (DEG_PER_FLOOR * floor));
// Set up to the floor (option 1)
//setRange(elevator_on, ELEVATOR_START, ELEVATOR_START + (LIGHTS_PER_FLOOR * floor));
//setRange(elevator_off, ELEVATOR_START + (LIGHTS_PER_FLOOR * floor), ELEVATOR_END);
// Set only the desired floor (option 2)
setRange(elevator_off, ELEVATOR_START, ELEVATOR_END);
setRange(elevator_on, ELEVATOR_START + (LIGHTS_PER_FLOOR * (floor-1)), ELEVATOR_START + (LIGHTS_PER_FLOOR * floor));
strip.show();
}
// Walk to a floor in steps - Walks one floor and sets timer if needed
void stepFloor() {
if(currentFloor > destinationFloor) {
setFloor(currentFloor - 1);
}
if(currentFloor < destinationFloor) {
setFloor(currentFloor + 1);
}
if(currentFloor != destinationFloor) {
floorTimer = millis() + FLOOR_DELAY;
}
}
void stepRainbow() {
int randNumber = random(300);
for(int i = ELEVATOR_START; i < ELEVATOR_END; i++) {
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + randNumber) & 255));
}
strip.show();
rainbowTimer = millis() + RAINBOW_DELAY;
}
int lastArrow = 0;
void stepArrow() {
int randNumber = 20 + random(140);
while(abs(lastArrow - randNumber) < 30) {
randNumber = 20 + random(140);
}
if(!arrowServo.attached()) {
arrowServo.attach(ARROW_PIN); // attaches the servo on a pin to the servo object
}
arrowServo.write(randNumber);
}
// ------------------------- Flux capacitor -------------------------
void stepFlux() {
int j;
setRange(flux_back, FLUX_START, FLUX_END);
for(j = 0; j < 3; j++) {
strip.setPixelColor(fluxPosition[fluxStep][j], flux_move);
}
strip.show();
fluxStep++;
if(fluxStep == 5) {
fluxStep = 0;
}
fluxTimer = millis() + FLUX_DELAY;
}
void startFlux() {
fluxTimer = millis() + FLUX_DELAY;
}
void setFluxColor(uint32_t color) {
setRange(color, FLUX_START, FLUX_END);
strip.show();
}
void setFluxPower(int power) {
if(power >= 2) {
flux_back = flux_back_high;
flux_move = flux_move_high;
debug("Power set to high");
} else {
flux_back = flux_back_low;
flux_move = flux_move_low;
debug("Power set to low");
}
}
// -------------------------------------------------------------------
// 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);
}
}
Comments