Saturday, April 10, 2010

Videos For My Bus Status Updater

Here are a few videos for the previous post. Sorry for the poor camera quality. All I have is a cameraphone to work with.



Most Useful Mess Of Wires: GPS Bus Notifier


Alright so I havent posted in a while, and the novelty of the wm+ has worn off. I dont have the funding to start a drone project right now, mainly since I’m a broke college student. And even if I did have the money, I dont think I would have the time this semester. I can barely manage to make it to classes right now. But it was from that problem that my last project took shape and has been helping me make it to my classes, making sure I dont fail out.

A little background info first: my city (Gainesville FL) recently put gps systems in most of their busses, which can be checked from the internet. Cool huh? It partially makes up for the fact that busses follow their schedule with an error of + or - 10 minutes (for a 40 minute route). While this is great, I found myself checking the computer every 30 seconds when I woke up, or my old computer would fail to shut down properly leaving it on all day while I wasnt home, not so good for a laptop. I wanted a way to be notified of when I actually had to get my butt out of the door and head to the bus, preferably without using my computer. Well, having just started to play around with the wiznet ethernet module (which comes on the arduino ethernet shield), I decided to make this my next project. So without further ado, I present the Bus Notifier!

I started by finding the static IP address for my bus's website, but since it is php based, the arduino obviously couldnt do anything with it. After mucking around, I found a text based version which was much more useful. The hardest parts of the project were creating a good string parsing algorithm to find just the info I wanted, and then figuring out which string tokens I wanted to make my program look for, signifying a change of state. The three states I decided upon were: nowhere near your apt, stopped somewhat close (for some reason my bus stops at one specific spot for like 10-15 minutes and just sits…yea really annoying) , and the last state is “the bus is coming, get out there!”. To allow me to know what state the bus(or busses) were in, I just used three leds, red, yellow, and green respectively. Later I added a piezo buzzer for the “get out there” state. It worked great for about three months in this state but eventually website updated and all my string parsing had to be redone. So on the next revision, I made the string parsing VERY easy to work with in case of later changes. It has been working this way every morning for the last three or so months.

Another kinda cool module I added was the ability to tweet the location of each of the busses every five minutes. I know this might seem stupid at first, but given the fact that twitter is very easy (and free) to check via text message, this allows me to check the location of the busses once I get out of class with nothing more than a “GET knuckles904” text message to twitter’s shortcode. It gives me the functionality of having a smartphone and internet plan without all the cost.

It took a lot of work, and several revisions to get everything working right but for the past 6 months, but of all the projects Ive spent time on, this has by far been the most useful. I feel I have actually gotten a return on my time investment on this one.

I am posting my most current code (just barely fits in a 168) below, as well as some links that are useful to see. Feel free to adapt any part of this code to your project. I am very proud of it, especially the new string searching function. Just please give credit where its due, and if possible link back here. Also as with all my other posts, any click to the “sponsors” on the right of the page is much appreciated.

http://www.arduino.cc/playground/Code/TwitterLibrary Makes Tweeting a cinch

http://ufl.transloc.com/ Gainesville’s GPS Bus website

http://ufl.transloc.com/t/ Text based version

http://www.nkcelectronics.com/wiznet-wiz812mj-tcpip-network-mod812.html Where I bought the Wiznet module

http://www.arduino.cc/en/Tutorial/TextString Libraries are there to make your lives easier

http://arduiniana.org/libraries/flash/ Thanks Mikal Hart for all your contributions

Dropboxed .pde of code I realized that the code wont necessarily work just by copy+paste, since there is embedded html in the pde. Use the scrollbox to view, and download the pde to run or modify.

CODE:







#include <Ethernet.h>
#include <WString.h>
#include <Twitter.h>
#include <Flash.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 1, 111 };
byte busServer[] = {66, 199, 240, 114 };

#define green 3 //pin definitions for leds and buzzer
#define yellow 4
#define red 5
#define buzzer 6

#define clientRefresh 20000 //just refresh times
#define buzzerRefresh 15000
#define twitterRefresh 300000
/*
char yellowstr[]="SE 20th Pl"; //means bus is waiting
char greenstr1[]="4th St"; //by itself means bus is on the move towards apt
char greenstr2[]="State Hwy 331"; //these two must be together
char greenstr3[]="Southwest"; //" " mean that bus is on the way to apt
char tagstr[]="";
char redstr1[]="SE 16th Ave"; //means that bus is already gone if contains this
char redstr2[]="West"; //and west
char redstr3[]="North"; //or redstr1 and this
*/


String timestring(28); //holding strings
String bus1Locationstring(100); //
String bus2Locationstring(100); //

String timesearch(7);//searching strings
String busSearch(16);

uint8_t connectStatus;
uint8_t closeStatus;
char readvalue=0;
unsigned long timer1=0; //client request timer
unsigned long timer2=0; //client timeout timer
unsigned long timer3=0; //buzzer timer
unsigned long timer4=0; //twitter timer
int state=0;

//FLASH_STRING(msg1, "i like pie");

Client busClient(busServer, 80);
Twitter twitter("****:****");//see twitter library for description
void makestring(char c, String &s);
//String getbackstring(const prog_char* str);

void setup()
{
initEthernet();
timer1=millis();
timer3=millis();
timer4=millis();
ConnectToWebserver();
state=makestate(state);
//Serial.print(F("Status: "));
//Serial.println(state);
clearstrings();
initPins();
}

void loop(){
if ((millis()-timer1)>clientRefresh){
ConnectToWebserver();
state=makestate(state);
//Serial.print(F("Status: "));
//Serial.println(state);
twitterupdate();
clearstrings();
timer1=millis();
}
switch (state){
case 0:
blink(red, 1000);
break;
case 1:
turnon(green);
if((millis()-timer3)>buzzerRefresh){
buzz(1000, 100);
timer3=millis();
}
break;
case 2:
turnon(yellow);
break;
case 3:
turnon(red);
break;
}
//Serial.println((millis()-timer4));
delay(1);
}


void ConnectToWebserver(){

uint8_t connectStatus;
if (busClient.connect()) {

Serial.println(F("-Connected"));

// Send the HTTP GET to the server
busClient.println(F("GET /t/route.php?id=66 HTTP/1.0")); //id=?? for php address
busClient.println();

timer2 = millis(); //secondary timer to wait up to five seconds for the server to respond
while ((!busClient.available()) && ((millis() - timer2 ) < style="color: #777755;">//loop until we either get a response or five seconds is up
// Read the response
while(busClient.available()>0){
readvalue=busClient.read();
while(busClient.available()>0&&timesearch.equals("")==false){
makestring(readvalue, timesearch);
readvalue=busClient.read();
//do nothing until find timestart tag
}
while(busClient.available()>0&&readvalue!='<'){
makestring(readvalue, timestring);
readvalue=busClient.read();
}
timesearch="";
while(busClient.available()>0&&busSearch.equals("
Bus 1
"
)==false){
makestring(readvalue, busSearch);
readvalue=busClient.read();
//do nothing until find bus1start tag
}
while(busClient.available()>0&&readvalue!='<'){
makestring(readvalue, bus1Locationstring);
readvalue=busClient.read();
}
busSearch="";
while(busClient.available()>0&&busSearch.equals("
Bus 2
"
)==false){
makestring(readvalue, busSearch);
readvalue=busClient.read();
//do nothing until find bus2start tag
}
while(busClient.available()>0&&readvalue!='<'){
makestring(readvalue, bus2Locationstring);
readvalue=busClient.read();
}
busSearch="";
}
/*
if(!timestring.equals("")){
//Serial.println(timestring);

}
if(!bus1Locationstring.equals("")){
//Serial.println(bus1Locationstring);

}
if(!bus2Locationstring.equals("")){
//Serial.println(bus2Locationstring);

}*/

// Disconnect from the server
busClient.flush();
busClient.stop();
//Serial.println(F("Connection ended"));

}
else {
// Connection failed
//Serial.println(F(" - CONNECTION FAILED!"));
timer1=millis();
}
}

int makestate(int state){
if(((bus1Locationstring.contains("4th St")&&!bus1Locationstring.contains("1"))||(bus1Locationstring.contains("State Hwy 331")&&bus1Locationstring.contains("Southwest")))||
((bus2Locationstring.contains("4th St")&&!bus2Locationstring.contains("1"))||(bus2Locationstring.contains("State Hwy 331")&&bus2Locationstring.contains("Southwest")))){
state=1;
}
else if(bus1Locationstring.contains("SE 20th Pl")||bus2Locationstring.contains("SE 20th Pl")){
state=2;
}
else if( ( (bus1Locationstring.contains("SE 16th Ave")&&bus1Locationstring.contains("West")) || (bus1Locationstring.contains("SE 16th Ave")&&bus1Locationstring.contains("North")) )||
( (bus2Locationstring.contains("SE 16th Ave")&&bus2Locationstring.contains("West")) || (bus2Locationstring.contains("SE 16th Ave")&&bus2Locationstring.contains("North")) ) ){
state=3;
}
return state;
}

void makestring(char inChar, String &inString) {
int maxLength=inString.capacity();
// read the incoming data as a char:
// if you're not at the end of the string, append
// the incoming character:
if (inString.length() < style="color: rgb(204, 102, 0);">else { //rolling string, taking out the first char and putting in a new one at the end
for(int i=0;ivoid buzz(int period, int number){
for (int i=0;idigitalWrite(buzzer, LOW);
delayMicroseconds(period/2);
digitalWrite(buzzer, HIGH);
delayMicroseconds(period/2);
}
}//we use 1000,100 for now

void blink(int pin, int duration){
digitalWrite(pin, HIGH);
delay(duration/2);
digitalWrite(pin, LOW);
delay(duration/2);
}

void initEthernet(){
pinMode(8, OUTPUT);
digitalWrite(8, HIGH);
delay(100);
digitalWrite(8, LOW);
delay(100);
digitalWrite(8, HIGH);
delay(5000);
Ethernet.begin(mac, ip);
Serial.begin(115200);
Serial.print(F("Start"));
}

void initPins(){
pinMode(green, OUTPUT);
pinMode(yellow, OUTPUT);
pinMode(red, OUTPUT);
pinMode(buzzer, OUTPUT);
digitalWrite(green, LOW);
digitalWrite(yellow, LOW);
digitalWrite(red, LOW);
}

void clearstrings(){
timestring="";
bus1Locationstring="";
bus2Locationstring="";
}

void turnon(int pin){
digitalWrite(green, LOW);
digitalWrite(yellow, LOW);
digitalWrite(red, LOW);
digitalWrite(pin, HIGH);
}

void turnoff(){
digitalWrite(green, LOW);
digitalWrite(yellow, LOW);
digitalWrite(red, LOW);
}

void twitterpost(int busnumber){
boolean good=0;
//Serial.println(F("connecting ..."));
if(busnumber==1){
good=twitter.post(bus1Locationstring);
}
else if(busnumber==2){
good=twitter.post(bus2Locationstring);
}
if (good) {
int status = twitter.wait();
if (status == 200) {
//Serial.println(F("OK.1"));
}
else {
//Serial.print(F("failed : code "));
//Serial.println(status);
}
}
else {
//Serial.println(F("connection failed."));
}
twitter.stop();
delay(1000);
}


void twitterupdate(){
if((millis()-timer4)>twitterRefresh){
if(!bus1Locationstring.equals("")){
twitterpost(1);
buzz(1000, 100);
delay(1000);
buzz(1000, 100);
delay(1000);
buzz(1000, 100);
}
if(!bus2Locationstring.equals("")){
twitterpost(2);
buzz(1000, 100);
delay(1000);
buzz(1000, 100);
delay(1000);
buzz(1000, 100);
}
timer4=millis();
}
}
/*
String getbackstring(const prog_char* str){
String tempstring(30);
//str.copy(tempstring, str.length());
return tempstring;
}
*/
/* //this whole sketch is based on the new ethernet client example
int ReadResponse(){
int totalBytes=0;
unsigned long timer2 = millis();

// First wait up to 5 seconds for the server to return some data.
// If we don't have this initial timeout period we might try to
// read the data "too quickly" before the server can generate the
// response to the request

while ((!busClient.available()) && ((millis() - timer2 ) <>

while (busClient.available()) {
char c = busClient.read();
Serial.print(c);
totalBytes+=1;
}
return totalBytes;
}
*/