Twitter Coffee Maker

Dependencies:   4DGL-uLCD-SE EthernetInterface HTTPClientAuthAndPathExtension mbed-rtos mbed

main.cpp

Committer:
tlisowski3
Date:
2014-04-23
Revision:
0:fe8909182706

File content as of revision 0:fe8909182706:

#include "mbed.h"
#include "rtos.h"
#include "EthernetInterface.h"
#include "HTTPClient.h"
#include "uLCD_4DGL.h"
#include <string>
#define TWOCUPS ((2*60)+19) //TIME to brew two cups (seconds)
#define FOURCUPS ((4*60)+7) //""
#define SIXCUPS ((5*60)+56) //""
#define POSTURL "http://143.215.102.83:8080/1.1/statuses/update.json" //URL TO POST NEW STATUS
#define GETURL "http://143.215.102.83:8080/1.1/statuses/mentions_timeline.json?count=1" //URL TO GET DATA
#define REQUESTINTRVL 60  //Interval to make get requests


void clientCheck();
string checkCupTweet(string wholeTweet);
void postTweet(string tweet);
string getField(int startIndex,int startLength);
void checkReady();
void brew();

DigitalIn ready(p5); //Ready pin
DigitalOut coffeeTurnOn(p6); //Coffee Turn on pin
EthernetInterface eth;
HTTPClient client;
uLCD_4DGL uLCD(p9,p10,p11); // serial tx, serial rx, reset pin;
char rawTweetInfo[8192];
string tweetInfo; //response from twitter
string previousID; //ID of preivously read tweet
string currentID; //ID of newest read tweet
string tweeter; //twitter handle of tweeter
string numCups; //Number of cups 
int state; //STATE MACHINE CONTROLLING PROCESS

int main() {
    state=5;
    ready.mode(PullUp);
    //Initialize Connection and get IP address
    eth.init();
    eth.connect();
    //Get inital information for current ID field
    clientCheck();
    uLCD.cls();
    uLCD.printf("Machine Needs coffee and water");
    wait(5.0);
    //End initalization
    while(1){
        //Check if the machine is ready to brew (accepts input from pushbutton)
        checkReady();
        //Check if new tweet has been sent and if its proper format
        clientCheck();
        //See if brew process should start
        brew(); //END 
    }  
}


void checkReady() {
    int loopVar=1000000000/2;
    while(loopVar>0){
        if(state>0) break;
        else{
            if(!(ready)){
                state=1;
                uLCD.cls();
                uLCD.printf("Machine Ready, waiting for Command");
            }
        }
        loopVar=loopVar-1;
    }
}

/*
    Post a tweet to twitter using the coffee machines handle.
    This allows us to notify the tweeter of our course of action.
    
    @param tweet- the tweet you are sending to the user

*/
void postTweet(string tweet){
        char str[512];
        int i;
        HTTPText inText(str, 512);
        HTTPMap mapp;
        mapp.put("status",tweet.c_str());
        for(i=0;i<2;i++){//TRY POSTING IT 3 TIMES OTHERWISE LET IT GO
            int ret=client.post(POSTURL, mapp, &inText);
            if (!ret)
            {
                uLCD.printf("Executed POST successfully - read characters\n");
                break;
            }
            else
            {
                uLCD.printf("Error Posting Data\n");
                tweet+=".";
                mapp.clear();
                mapp.put("status",tweet.c_str());
                wait(2.0);
                continue;
            }
        }
}
/*
    Gets the value of a field sent back from twitter through an HTTP get request.
    The data is in JSON format and can be parsed accordingly. 
    
    @param startIndex- starting index in response (of header)
    @param startLength- the length of the header (in characters)
    
    return
    finalResult- the value of the field as a string
    
*/
string getField(int startIndex,int startLength){
    int start=startIndex+startLength+1; //should be first letter
    char curChar=tweetInfo.at(start); //first letter
    string finalResult=""; 
    while(curChar !='\"'){
        finalResult+=curChar;
        start=start+1;
        curChar=tweetInfo.at(start);
    }
    return finalResult;
}

/*
    Gets the newest tweet from the coffee Machines twitter feed.
    Responds to the tweet based on the current state of the coffee machine
    and whether the tweet was in the proper format or not.
*/
void clientCheck(){
    int ret = client.get(GETURL,rawTweetInfo,4096); //Do HTTP GET REQUEST
    double rqstInt=REQUESTINTRVL;
    if (ret) { //IF Request failed
        uLCD.cls();
        uLCD.printf("FAIL GETTING DATA\n");
        uLCD.printf("ERROR= %d\n",ret);
        uLCD.printf("Error - ret = %d - HTTP return code = %d\n", ret, client.getHTTPResponseCode());
        wait(rqstInt);
        return;
    }
    tweetInfo=rawTweetInfo;
    string tweeterStart="\"screen_name\":"; //Header in request for twitter handle
    string numCupsStart="\"text\":"; //Header in request for tweet
    string idStart="\"id_str\":"; //Header in request for the unique ID with every tweet
    int indexID=tweetInfo.find(idStart,0);
    int indexTweeter=tweetInfo.find(tweeterStart,0);
    int indexNumCups=tweetInfo.find(numCupsStart,0);
    int tweeterLength=tweeterStart.length();
    int cupsLength=numCupsStart.length();
    int idLength=idStart.length();     
    //Get the idString
    string tempID=getField(indexID,idLength);
    if(strcmp(tempID.c_str(),currentID.c_str())==0);//do nothing, no new tweet
    else{//got a new tweet
        previousID=currentID;
        currentID=tempID;
        string tempTweeter=getField(indexTweeter,tweeterLength); //NEED TO ADD @ Symbol
        tempTweeter=tempTweeter.insert(0,"@"); //Insert at symbol
        if(state==2){//already brewing
            tempTweeter+=" Currently brewing try again later";
            postTweet(tempTweeter);
        }
        else if(state==0){//Not ready so notify the machine is not ready
            tempTweeter+=" Coffee Machine not Ready. Needs Water and Grinds";
            postTweet(tempTweeter);
        }
        else if(state==5) state=0; //Initialization state
        else{
            //Check if its a valid cup tweet
            //Get the whole tweet
            string wholeTweet=getField(indexNumCups,cupsLength);
            string tempCup=checkCupTweet(wholeTweet);
            if(strcmp(tempCup.c_str(),"inv")==0){ //Invalid format. Notify user
                tempTweeter+=" Invalid Format. Use <handle> <numcups> cups";
                postTweet(tempTweeter);
            }
            else{//ALL GOOD SET EVERYTHING
                numCups=tempCup;
                tweeter=tempTweeter;
                state=3;
            }
        }
    }
    wait(rqstInt); 
}
/*
    Extracts the number of cups specified in a tweet to the coffee maker.
    If no valid number, sets the cups field as inv.
    
    @param wholeTweet- tweet that a user sent to the coffee machine
    
    return
    result- a string with either the number of cups in the tweet or inv

*/
string checkCupTweet(string wholeTweet){
    string subTweet;
    string result;
    char curChar=wholeTweet.at(0);
    if(curChar!='@'){
        result="inv";
    }
    else{
        while(curChar!=' '){
            wholeTweet.erase(0,1);
            curChar=wholeTweet.at(0);   
        }
        subTweet=wholeTweet;
        if(subTweet.find_first_of("2",0) != string::npos){
            result="2";    
        }
        else if(subTweet.find_first_of("4",0) != string::npos){
            result="4";
        }
        else if(subTweet.find_first_of("6",0) != string::npos){
            result="6";
        }
        else{
            result="inv";
        }
    }
    return result;    
}



/*
    Handles the brewing process. Checks if the state is set to the proper value (3)
    and then goes through the brewing process. If it is not the proper state, simply
    exits the function.
*/
void brew(){
    double rqstInt=REQUESTINTRVL;
    if(state==3){//DO THE BREW
        uLCD.cls();
        uLCD.printf("BREWING");
        int numTimes;
        int i;
        double remainder;
        int timeToBrew;
        state=2;
        string sendTweet=tweeter;
        sendTweet+=" Starting to brew!";
        postTweet(sendTweet);
        coffeeTurnOn=1;
        if(strcmp(numCups.c_str(),"2")==0){
            timeToBrew=TWOCUPS;
            numTimes=timeToBrew/rqstInt;
            remainder= timeToBrew % ((int)rqstInt);
            for(i=0;i<numTimes;i++){
                clientCheck();
            }
            wait(remainder);
        }
        else if(strcmp(numCups.c_str(),"4")==0){
            numTimes=FOURCUPS/rqstInt;
            remainder= FOURCUPS % ((int)rqstInt);
            for(i=0;i<numTimes;i++){
                clientCheck();
            }
            wait(remainder);
        }
        else if(strcmp(numCups.c_str(),"6")==0){
            numTimes=SIXCUPS/rqstInt;
            remainder= SIXCUPS % ((int)rqstInt);  
            for(i=0;i<numTimes;i++){
                clientCheck();
            }
            wait(remainder);  
        }
        sendTweet=tweeter;
        sendTweet+=" done brewing. Enjoy!";
        postTweet(sendTweet);
        coffeeTurnOn=0;
        state=0;  
    }
    else;     
}