Wi-Fi enabled automatic drink mixer. Open up the webpage, select you drink and/or mixer and hit dispense. Be amazed as it mixes your drinks for you! Extendable and customizable.
Fork of ECE_4180_Lab_4_Robot_Webserver by
main.cpp
- Committer:
- anewton8
- Date:
- 2015-12-06
- Revision:
- 6:5c3c1f1c2985
- Parent:
- 5:cfceccd5ccb1
File content as of revision 6:5c3c1f1c2985:
// ESP8266 Static page WEB server to control Mbed #include "mbed.h" #include "rtos.h" Serial pc(USBTX, USBRX); RawSerial esp(p28, p27); // tx, rx DigitalOut reset(p29); // Reset for esp // Standard Mbed LED definitions DigitalOut led1(LED1); // (PTB18) DigitalOut led2(LED2); // (PTB19) DigitalOut led3(LED3); // (PTD1) DigitalOut led4(LED4); DigitalIn pb(p8); // Drink stuff #define TYPE_DRINK 0 #define TYPE_MIXER 1 #define RELAY_NONE -1 #define DRINK_RELAY_WHISKY 0 #define DRINK_RELAY_GIN 1 #define MIXER_RELAY_COKE 2 #define MIXER_RELAY_TONIC 3 DigitalOut gRelays[] = {p22, p23, p24, p25}; // Relay Pins int gDrinkRelayVal = RELAY_NONE; int gMixerRelayVal = RELAY_NONE; int gPourLatch = false; void startPour(int type, int drinkRelay, float timeMs); void stopDrinkPour(void const *args); void stopMixerPour(void const *args); RtosTimer *gStopDrinkTimer; RtosTimer *gStopMixerTimer; // Webserver stuff Timer t1; Timer t2; struct tm t; int bufflen, DataRX, count, getcount, replycount, servreq, timeout; int bufl, ipdLen, linkID, weberror, webcounter; char webcount[8]; char lasthit[30]; char timebuf[30]; char type[16]; char type1[16]; char channel[2]; char cmdbuff[32]; char replybuff[4096]; char webdata[4096]; // This may need to be bigger depending on WEB browser used char webbuff[8192]; // Currently using 1986 characters, Increase this if more web page data added void SendCMD(),getreply(),ReadWebData(),startserver(),sendpage(),SendWEB(),sendcheck(); void setRTC(); void otherThread(void const *args); // manual set RTC values int minute =00; // 0-59 int hour =12; // 2-23 int dayofmonth =26; // 1-31 int month =8; // 1-12 int year =15; // last 2 digits int port =80; // set server port int SERVtimeout =5; // set server timeout in seconds in case link breaks. // Serial Interrupt read ESP data void callback() { led3=1; led4 = 0; while (esp.readable()) { led4 = !led4; webbuff[count] = esp.getc(); count++; } led2 = 0; if(strlen(webbuff)>bufflen) { DataRX=1; led3=0; } } // Stop drink relay void stopDrinkPour(void const *args) { //drinkTimer.detach(); gRelays[gDrinkRelayVal] = 0; gDrinkRelayVal = RELAY_NONE; // pc.printf("Relays: %d,%d,%d,%d\n\r", gRelays[0], gRelays[1], gRelays[2], gRelays[3]); } void stopMixerPour(void const *args) { //mixerTimer.detach(); gRelays[gMixerRelayVal] = 0; gMixerRelayVal = RELAY_NONE; // pc.printf("Relays: %d,%d,%d,%d\n\r", gRelays[0], gRelays[1], gRelays[2], gRelays[3]); } void startPour(int type, int relayVal, float timeMs) { switch (relayVal) { case DRINK_RELAY_WHISKY: case DRINK_RELAY_GIN: case MIXER_RELAY_COKE: case MIXER_RELAY_TONIC: // Good values break; case RELAY_NONE: return; // Do nothing for this pour default: pc.printf("StartPour invalid relay val %d!\n\r", relayVal); return; } // Pour! gRelays[relayVal] = 1; //pc.printf("Relays: %d,%d,%d,%d\n\r", gRelays[0], gRelays[1], gRelays[2], gRelays[3]); if (type == TYPE_DRINK) { //drinkTimer.attach(&stopDrinkPour, 1.0); gStopDrinkTimer->start(1000); } else if (type == TYPE_MIXER) { //mixerTimer.attach(&stopMixerPour, 0.5); gStopMixerTimer->start(500); } } void otherThread(void const *args) { pb.mode(PullUp); RtosTimer stopDrinkTimer(stopDrinkPour, osTimerOnce); RtosTimer stopMixerTimer(stopMixerPour, osTimerOnce); gStopDrinkTimer = &stopDrinkTimer; gStopMixerTimer = &stopMixerTimer; while (1) { if (gPourLatch) { startPour(TYPE_DRINK, gDrinkRelayVal, 1000); startPour(TYPE_MIXER, gMixerRelayVal, 500); gPourLatch = false; } //gRelays[0] = !pb; Thread::wait(50); } } int main() { gRelays[0] = 0; gRelays[1] = 0; gRelays[2] = 0; gRelays[3] = 0; Thread tT(otherThread); reset=0; pc.baud(115200); pc.printf("\f\n\r------------ ESP8266 Hardware Reset --------------\n\r"); wait(0.5); reset=1; led1=1,led2=0,led3=0; timeout=6000; getcount=500; getreply(); esp.baud(115200); // ESP8266 baudrate. Maximum on KLxx' is 115200, 230400 works on K20 and K22F if (time(NULL) < 1420070400) { setRTC(); } startserver(); //Thread tPourThread(pourThread); while(1) { if(DataRX==1) { ReadWebData(); if (servreq == 1 && weberror == 0) { sendpage(); } esp.attach(&callback); pc.printf(" IPD Data:\r\n\n Link ID = %d,\r\n IPD Header Length = %d \r\n IPD Type = %s\r\n", linkID, ipdLen, type); pc.printf("\n\n HTTP Packet: \n\n%s\n", webdata); pc.printf(" Web Characters sent : %d\n\n", bufl); pc.printf(" -------------------------------------\n\n"); strcpy(lasthit, timebuf); servreq=0; } } } // Static WEB page void sendpage() { // WEB page data strcpy(webbuff, "\ <html>\ <head>\ <meta name='viewport' content='width=device-width; initial-scale=1.0; maximum-scale=1.0;'>\ <title>Sir MixaBot</title>\ <link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css' integrity='sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7' crossorigin='anonymous'>\ <style>\ body {\ background: url(http://i.imgur.com/NrfPRXU.jpg?1);\ background-size: cover;\ background-repeat: no-repeat;\ }\ select {\ width: 100%;\ }\ .center {\ margin: auto;\ }\ .container {\ display:inline-block;\ }\ h1 {\ font-family: 'Lucida Bright', Georgia, serif;\ font-size: 72px;\ font-style: normal;\ font-variant: normal;\ font-weight: 400;\ line-height: 60px;\ color: rgba(100, 100, 100, 1.0);\ -webkit-text-stroke: 1px black;\ background: rgba(255, 255, 255, 0.9);\ background-size: contain;\ padding: 5px;\ } \ form {\ width: 200px;\ margin-top: 10px;\ background: rgba(255, 255, 255, 0.9);\ background-size: contain;\ -webkit-box-shadow: 10px 10px 10px rgba(0, 0, 0, 0.7);\ -moz-box-shadow: 10px 10px 10px rgba(0, 0, 0, 0.7);\ box-shadow: 10px 10px 10px rgba(0, 0, 0, 0.7);\ border-radius: 8px;\ padding: 8px;\ font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Lucida Sans', Geneva, Verdana, sans-serif;\ font-size: 14px;\ font-style: normal;\ font-variant: normal;\ font-weight: 400;\ line-height: 20px;\ }\ </style>\ </head>\ <body>\ <h1>Sir MixaBot</h1>\ <div class='container'>\ <form method='POST'>\ <label>Drink</label>\ <select name='drink'>\ <option value=''>-- None --</option>\ <option value='whisky'>Whisky</option>\ <option value='gin'>Gin</option>\ </select>\ <br />\ <br />\ <label>Mixer</label>\ <select name='mixer'>\ <option value=''>-- None --</option>\ <option value='coke'>Coke</option>\ <option value='tonic'>Tonic</option>\ </select> \ <br />\ <br />\ <button type='submit' class='btn btn-block btn-lg btn-danger'>Dispense</button>\ </form>\ </div>\ </body>\ </html>"); // end of WEB page data bufl = strlen(webbuff); // get total page buffer length sprintf(cmdbuff,"AT+CIPSEND=%d,%d\r\n", linkID, bufl); // send IPD link channel and buffer character length. timeout=200; getcount=7; SendCMD(); getreply(); SendWEB(); // send web page memset(webbuff, '\0', sizeof(webbuff)); sendcheck(); } // wait for ESP "SEND OK" reply, then close IP to load web page void sendcheck() { weberror=1; timeout=500; getcount=24; t2.reset(); t2.start(); while(weberror==1 && t2.read() <5) { getreply(); if (strstr(replybuff, "SEND OK") != NULL) { weberror=0; // wait for valid SEND OK } } if(weberror==1) { // restart connection strcpy(cmdbuff, "AT+CIPMUX=1\r\n"); timeout=500; getcount=10; SendCMD(); getreply(); pc.printf(replybuff); sprintf(cmdbuff,"AT+CIPSERVER=1,%d\r\n", port); timeout=500; getcount=10; SendCMD(); getreply(); pc.printf(replybuff); } else { sprintf(cmdbuff, "AT+CIPCLOSE=%s\r\n",channel); // close current connection SendCMD(); getreply(); pc.printf(replybuff); } t2.reset(); } // Reads and processes GET and POST web data void ReadWebData() { wait_ms(200); esp.attach(NULL); count=0; DataRX=0; weberror=0; memset(webdata, '\0', sizeof(webdata)); int x = strcspn (webbuff,"+"); if(x) { pc.printf("DATA: %s", webdata); strcpy(webdata, webbuff + x); weberror=0; int numMatched = sscanf(webdata,"+IPD,%d,%d:%s", &linkID, &ipdLen, type); sprintf(channel, "%d",linkID); if (strstr(webdata, "GET") != NULL) { servreq=1; } if (strstr(webdata, "POST") != NULL) { int drinkVal = RELAY_NONE; int mixerVal = RELAY_NONE; if(strstr(webdata, "drink=whisky") != NULL) { drinkVal = DRINK_RELAY_WHISKY; } else if (strstr(webdata, "drink=gin") != NULL ) { drinkVal = DRINK_RELAY_GIN; } if(strstr(webdata, "mixer=coke") != NULL) { mixerVal = MIXER_RELAY_COKE; } else if (strstr(webdata, "mixer=tonic") != NULL ) { mixerVal = MIXER_RELAY_TONIC; } if (gDrinkRelayVal == RELAY_NONE && gMixerRelayVal == RELAY_NONE) { gDrinkRelayVal = drinkVal; gMixerRelayVal = mixerVal; gPourLatch = true; } servreq=1; } webcounter++; sprintf(webcount, "%d",webcounter); } else { memset(webbuff, '\0', sizeof(webbuff)); esp.attach(&callback); weberror=1; } } // Starts and restarts webserver if errors detected. void startserver() { pc.printf("\n\n RTC time %s\r\n\n",timebuf); pc.printf("++++++++++ Resetting ESP ++++++++++\r\n"); strcpy(cmdbuff,"AT+RST\r\n"); timeout=8000; getcount=1000; SendCMD(); getreply(); pc.printf(replybuff); pc.printf("%d",count); if (strstr(replybuff, "OK") != NULL) { pc.printf("\n++++++++++ Starting Server ++++++++++\r\n"); strcpy(cmdbuff, "AT+CIPMUX=1\r\n"); // set multiple connections. timeout=500; getcount=20; SendCMD(); getreply(); pc.printf(replybuff); sprintf(cmdbuff,"AT+CIPSERVER=1,%d\r\n", port); timeout=500; getcount=20; SendCMD(); getreply(); pc.printf(replybuff); wait(1); sprintf(cmdbuff,"AT+CIPSTO=%d\r\n",SERVtimeout); timeout=500; getcount=50; SendCMD(); getreply(); pc.printf(replybuff); wait(5); pc.printf("\n Getting Server IP \r\n"); strcpy(cmdbuff, "AT+CIFSR\r\n"); timeout=2500; getcount=200; while(weberror==0) { SendCMD(); getreply(); if (strstr(replybuff, "0.0.0.0") == NULL) { weberror=1; // wait for valid IP } } pc.printf("\n Enter WEB address (IP) found below in your browser \r\n\n"); pc.printf("\n The MAC address is also shown below,if it is needed \r\n\n"); replybuff[strlen(replybuff)-1] = '\0'; //char* IP = replybuff + 5; sprintf(webdata,"%s", replybuff); pc.printf(webdata); led2=1; bufflen=200; count=0; pc.printf("\n\n++++++++++ Ready ++++++++++\r\n\n"); esp.attach(&callback); } else { pc.printf("\n++++++++++ ESP8266 error, check power/connections ++++++++++\r\n"); while(1) {} } t2.reset(); t2.start(); } // ESP Command data send void SendCMD() { esp.printf("%s", cmdbuff); } // Large WEB buffer data send void SendWEB() { int i=0; if(esp.writeable()) { while(webbuff[i]!='\0') { esp.putc(webbuff[i]); i++; } } } // Get Command and ESP status replies void getreply() { memset(replybuff, '\0', sizeof(replybuff)); t1.reset(); t1.start(); replycount=0; while(t1.read_ms()< timeout && replycount < getcount) { if(esp.readable()) { replybuff[replycount] = esp.getc(); replycount++; } } t1.stop(); } void setRTC() { t.tm_sec = (0); // 0-59 t.tm_min = (minute); // 0-59 t.tm_hour = (hour); // 0-23 t.tm_mday = (dayofmonth); // 1-31 t.tm_mon = (month-1); // 0-11 "0" = Jan, -1 added for Mbed RCT clock format t.tm_year = ((year)+100); // year since 1900, current DCF year + 100 + 1900 = correct year set_time(mktime(&t)); // set RTC clock }