/* P4Groan. Simple web server with connected 16x2 LCD A simple web server that shows and changes the value of the Groan Index in a browser an well as on connected LCD Circuit: * LCD on pins 2,3,4,5,6,7 * Ethernet shield attached to pins 10, 11, 12, 13 * Servo on PWM pin 9 Author: Simon West Created: 2012-08-24. Perforce Workshop initial addition: 2014-08-01 */ #define DEBUG 1 // Various defines... // The IP address will be dependent on your local network // Made a defined to allow for future use of DHCP #define useLCD 1 // #define staticIP 169,254,10,75 // Use servo? #define useServo 1 // Limits - must be a multiple of 180 is using servo to make mapping work cleanly #define MAXGROAN 180 // Includes needed for Ethernet shield #include #include #if defined useServo // Servo control library #include Servo pointerArm; #endif // Optionally include LCD code #if defined useLCD #include // initialize the library with the numbers of the interface pins LiquidCrystal lcd(7,6,5,4,3,2); boolean activityIndicator = true; #endif // Enter a MAC address and IP address for your controller below. byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; #if defined staticIP IPAddress ip(staticIP); #endif // Holds the GrownLevel int groanLevel = 0; // Initialize the Ethernet server library EthernetServer server(80); void setup() { // start the Ethernet connection and the server: Serial.begin(9600); Serial.println("Starting"); #if defined useLCD lcd.begin(16,2); lcd.print("starting"); #endif // start the Ethernet connection: #if defined staticIP Ethernet.begin(mac,ip); #else if (Ethernet.begin(mac) == 0) { Serial.println("Failed to configure Ethernet using DHCP"); #if defined useLCD lcd.clear(); lcd.print("DHCP not available"); lcd.setCursor(0,1); lcd.print("**Game Over**"); #endif // no point in carrying on, so do nothing forevermore: for(;;) ; } #endif // Output the IP address on LCD and debug #if defined useLCD lcd.clear(); lcd.print("IP:"); lcd.setCursor(0,1); #endif // print your local IP address: Serial.print("My IP address: "); for (byte thisByte = 0; thisByte < 4; thisByte++) { // print the value of each byte of the IP address: Serial.print(Ethernet.localIP()[thisByte], DEC); Serial.print("."); #if defined useLCD lcd.print(Ethernet.localIP()[thisByte], DEC); lcd.print("."); #endif } Serial.println(); #if defined useServo //Connect to the servo #if defined DEBUG Serial.println("Init pointer"); #endif pointerArm.attach(9); setArmPosition(groanLevel); #endif // Start the ethernet server server.begin(); #if defined useLCD // Wait for 2 secs to for mesage to be read on LCD delay(2000); // wait 2 secs // initial display and we're ready to go... lcd.clear(); lcd.print("Perforce Groans"); lcd.setCursor(0,1); lcd.print("Groan Index:"); lcd.print(groanLevel); #endif } void loop() { readStream(); #if defined useLCD blinkScreen(); #endif } int readStream() { char pageRequested; boolean validLine = false; // listen for incoming clients EthernetClient client = server.available(); if (client) { // an http request ends with a blank line boolean currentLineIsBlank = true; String ln = ""; while (client.connected()) { if (client.available()) { char c = client.read(); #if defined DEBUG Serial.print(c); #endif // if you've gotten to the end of the line (received a newline // character) and the line is blank, the http request has ended, // so you can send a reply if (c == '\n' && currentLineIsBlank) { sendPage(client, pageRequested); #if defined useLCD updateLCD(); #endif #if defined useServo if (pageRequested == 'i'|| pageRequested == 'j'|| pageRequested =='r') { // do this after sending page to stop browser having to wait for arm to position itself... setArmPosition(groanLevel); } #endif break; } // end if get line if (c == '\n') { // you're starting a new line currentLineIsBlank = true; ln = ""; } // end if starting new line else if (c != '\r') { // you've gotten a character on the current line currentLineIsBlank = false; ln += c; // catches the fact that some browsers request /faveico or /applemobileicon as a 2nd request. we ignore these if (!validLine) { validLine = (ln == "GET /i " || ln == "GET / " || ln == "GET /r " || ln == "GET /j "); if (validLine) { pageRequested = ln.charAt(5); } } // if !validLine } // end else if } // end if (client.available()) } // end while // give the web browser time to receive the data delay(1); // close the connection: client.stop(); } } void sendPage(EthernetClient client, char pageRequested) { String mess = "
"; // send a standard http response header client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println(); // output the page client.print("

Perforce Groan-o-meter

"); if (pageRequested == 'i') { // Increment mess = "By visiting this page you have increased the Groan-o-meter...
"; ++groanLevel; } if (pageRequested == 'j') { // jump the increment by 10 mess = "Wow! That bad? Groan-o-meter increased by 10!
"; groanLevel = groanLevel + 10; } if (pageRequested == 'r') { // reset mess = "Really? Someone laughed? OK... resetting...
"; groanLevel = 0; } // Always display the help and value client.print("

Groan level is now "); client.print(groanLevel); client.print("

"); client.print(mess); client.print("
You can Display current Groan level
"); client.print("or you can Increase the Groan level by 1 or even Increase the Groan level by 10
"); client.print("You can even Reset if you really must
"); client.print(""); } #if defined useLCD void updateLCD() { lcd.setCursor(12,1); lcd.print(" "); lcd.setCursor(12,1); lcd.print(groanLevel); } void blinkScreen() { if (millis()%1000 == 0) { lcd.setCursor(15,0); if (activityIndicator) { lcd.print('.'); } else { lcd.print(' '); } } activityIndicator = !activityIndicator; } #endif #if defined useServo void setArmPosition(int armPos) { #if defined DEBUG Serial.println(""); Serial.print("Setting arm to:"); Serial.println(armPos); Serial.println(""); #endif int swipeDelay; int currentPos = pointerArm.read(); // use variable timing for arm sweep. make is faster the further it needs to travel if (currentPos >= 135) { swipeDelay = 9; } else if (currentPos >= 90) { swipeDelay = 7; } else if (currentPos >= 45) { swipeDelay = 5; } else { swipeDelay = 3; } // As the pointer and groanindex run on different scales we need to remap the value to between 0 and 180. The index can continue to increase but the arm sweep will stop at 180. armPos = map(armPos,0,MAXGROAN,179,0); for(int pos = currentPos; pos < 180; pos += 1) // goes from 0 degrees to 180 degrees { // in steps of 1 degree pointerArm.write(pos); // tell servo to go to position in variable 'pos' delay(swipeDelay); // waits 15ms for the servo to reach the position } for(int pos = 179; pos>=armPos; pos-=1) // goes from 180 degrees to 0 degrees { pointerArm.write(pos); // tell servo to go to position in variable 'pos' delay(swipeDelay); // waits 15ms for the servo to reach the position } } // setArmPosition #endif