A sprinkler controller that takes HTTP command for zone and duration.

Dependencies:   EthernetNetIf mbed HTTPServer

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sprinkler_handler.cpp Source File

sprinkler_handler.cpp

00001 /*
00002 Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
00003  
00004 Permission is hereby granted, free of charge, to any person obtaining a copy
00005 of this software and associated documentation files (the "Software"), to deal
00006 in the Software without restriction, including without limitation the rights
00007 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008 copies of the Software, and to permit persons to whom the Software is
00009 furnished to do so, subject to the following conditions:
00010  
00011 The above copyright notice and this permission notice shall be included in
00012 all copies or substantial portions of the Software.
00013  
00014 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00017 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00019 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00020 THE SOFTWARE.
00021 */
00022 
00023 #include "sprinkler_handler.h"
00024 #include "share.h"
00025 #include <string>
00026 #include <cstring>
00027 
00028 //#define __DEBUG
00029 #include "dbg/dbg.h"
00030 
00031 // there are only 4 zones for this sprinkler controller
00032 Timer zone1Timer;   // timers are used here, and they only go for about 30 minutes
00033 Timer zone2Timer;   // so this is not good for hours...
00034 Timer zone3Timer;
00035 Timer zone4Timer;
00036 float zone1Interval;
00037 float zone2Interval;
00038 float zone3Interval;
00039 float zone4Interval;
00040 Timeout zone1Timeout;
00041 Timeout zone2Timeout;
00042 Timeout zone3Timeout;
00043 Timeout zone4Timeout;
00044 
00045 SprinklerHandler::SprinklerHandler(const char* rootPath, 
00046                                 const char* path, 
00047                                 TCPSocket* pTCPSocket) : HTTPRequestHandler(rootPath,
00048                                                                         path,
00049                                                                         pTCPSocket)
00050 {
00051 
00052 }
00053 
00054 SprinklerHandler::~SprinklerHandler()
00055 {
00056   DBG("\r\nHandler destroyed\r\n");
00057 }
00058 
00059 void SprinklerHandler::doGet()
00060 {
00061   char resp[300];
00062  
00063   DBG("\r\nIn SprinklerHandler::doGet()\r\n");  
00064   lanActivity();
00065   // just output the current timer values for each zone
00066   const char * match;
00067   if ((match = strstr( path().c_str(), "zone1")) > 0) {
00068         sprintf( resp, "zone1=%f\n", zone1Timer.read() );
00069   } else if ((match = strstr( path().c_str(), "zone2")) > 0 ) {
00070         sprintf(  resp, "zone2=%f\n", zone2Timer.read() );
00071   } else if ((match = strstr( path().c_str(), "zone3")) > 0 ) {
00072        sprintf(  resp, "zone3=%f\n", zone3Timer.read() );
00073   } else if ((match = strstr( path().c_str(), "zone4")) > 0 ) {
00074         sprintf(  resp, "zone4=%f\n", zone4Timer.read() );
00075   } else {      // assume they want all the status
00076        sprintf( resp, "zone1=%f\nzone2=%f\nzone3=%f\nzone4=%f\n",
00077             zone1Timer.read(), zone2Timer.read(), zone3Timer.read(), zone4Timer.read() );
00078   }
00079 
00080   setContentLen( strlen(resp) ); 
00081   respHeaders()["Connection"] = "close";
00082   respHeaders()["Content-type"] = "text/html";
00083   writeData(resp, strlen(resp));
00084   DBG("\r\nExit SprinklerHandler::doGet()\r\n");
00085 }
00086 
00087 void SprinklerHandler::doPost()
00088 {
00089  char data[128];
00090  string str = "POST path is " + path() + "\n";
00091  int maxlen = dataLen();
00092  if (maxlen > 127) { maxlen = 127; }
00093  int len = readData( data, maxlen );
00094  data[maxlen] = 0;
00095  string d = data;
00096  str += "and data is " + d + "\n";
00097  
00098  lanActivity();
00099  // find out if it's a reset or start
00100  const char * match = strstr( path().c_str(), "reset");
00101  if  (match > 0) {         // must be reset
00102     // handle reset
00103     zone1Timer.stop();
00104     zone2Timer.stop();
00105     zone3Timer.stop();
00106     zone4Timer.stop();
00107     compute1out = 0;
00108     compute2out = 0;
00109     compute3out = 0;
00110     compute4out = 0;
00111     // cancel any pending timer interrupts
00112     zone1Timeout.detach();
00113     zone2Timeout.detach();
00114     zone3Timeout.detach();
00115     zone4Timeout.detach();
00116     zone1Interval = 0;
00117     zone2Interval = 0;
00118     zone3Interval = 0;
00119     zone4Interval = 0;
00120     str = "OK";
00121     DBG("\r\nreset called\r\n");
00122   } else if ((match = strstr( path().c_str(), "start")) > 0) {    // must be start
00123     // get zone and duration from message - example:  zone=1&duration=300
00124      map<string, string> params;
00125     char line[128];
00126     char key[128];
00127     char value[128];
00128     char * from = data;
00129     while( parsekv(&from, line, 128) > 0) //if == 0, it is an empty line = end of headers
00130         {
00131          int n = sscanf(line, "%[^=]=%[^\n]", key, value);
00132          if ( n == 2 )
00133             {
00134             DBG("Read params : %s : %s\r\n", key, value);
00135              params[key] = value;
00136             }
00137         }   
00138     // get duration
00139     if (atoi(params["zone"].c_str()) < 1  || atoi(params["zone"].c_str()) > 4) {
00140         str = "unknown zone";
00141     } else {
00142         if (atoi(params["duration"].c_str()) <= 0) {
00143             str = "invalid duration";
00144         } else {
00145             int dur = atoi(params["duration"].c_str());
00146             switch (atoi(params["zone"].c_str())) {
00147                 case 1:
00148                     zone1Timer.reset();
00149                     zone1Timer.start();
00150                     compute1out = 1;
00151                     zone1Interval = dur;
00152                     zone1Timeout.attach( this, &SprinklerHandler::turnOffZone1, dur );
00153                     break;
00154                     
00155                 case 2:
00156                     zone2Timer.reset();
00157                     zone2Timer.start();
00158                     compute2out = 1;
00159                     zone2Interval = dur;
00160                     zone2Timeout.attach( this, &SprinklerHandler::turnOffZone2, dur );
00161                     break;
00162                     
00163                 case 3:
00164                     zone3Timer.reset();
00165                     zone3Timer.start();
00166                     compute3out = 1;
00167                     zone3Interval = dur;
00168                     zone3Timeout.attach( this, &SprinklerHandler::turnOffZone3, dur );
00169                     break;
00170                     
00171                 case 4:
00172                     zone4Timer.reset();
00173                     zone4Timer.start();
00174                     compute4out = 1;
00175                     zone4Interval = dur;
00176                     zone4Timeout.attach( this, &SprinklerHandler::turnOffZone4, dur );
00177                     break;
00178                     
00179                 default:
00180                     str = "bad zone in case statement";
00181                     break;
00182             }
00183         }
00184     }
00185  
00186     DBG("\r\nstart called\r\n");
00187   }
00188   
00189   const char * resp = str.c_str(); 
00190   setContentLen( strlen(resp) );
00191   respHeaders()["Content-type"] = "text/html";
00192   respHeaders()["Connection"] = "close";
00193   writeData(resp, strlen(resp));
00194   DBG("\r\nExit SprinklerHandler::doPost()\r\n");
00195 }
00196 
00197 // taken from the HTTP parsing code
00198 int SprinklerHandler::parsekv( char **from, char *to, int max ) {
00199     /*
00200      * look for & or \n and return key=value line
00201      */
00202      char *end;
00203      int retval = 0;
00204      
00205      end = strstr( *from, "&" );
00206      if (end) {
00207         int len = (end - *from);
00208         strncpy( to, *from, len);
00209         to[len] = 0;
00210         *from += len + 1;
00211         DBG("parsekv sending back %s\r\n", to);
00212         retval = 1;
00213      } else {
00214         // maybe this was the last parameter
00215         if (strstr(*from, "=")) {
00216             strncpy( to, *from, strlen(*from));
00217             to[strlen(*from)] = 0;
00218             *from += strlen(*from);
00219             DBG("parsekv sending back %s\r\n", to);
00220             retval = 1;
00221         }
00222         // nope, nothing left, just fall through and return 0
00223      }
00224     return retval;
00225 }
00226 
00227 void SprinklerHandler::doHead()
00228 {
00229 
00230 }
00231 
00232 void SprinklerHandler::onReadable() //Data has been read
00233 {
00234 
00235 }
00236 
00237 void SprinklerHandler::onWriteable() //Data has been written & buf is free
00238 {
00239   DBG("\r\nSimpleHandler::onWriteable() event\r\n");
00240   close(); //Data written, we can close the connection
00241 }
00242 
00243 void SprinklerHandler::onClose() //Connection is closing
00244 {
00245   //Nothing to do
00246 }
00247 
00248 void SprinklerHandler::turnOffZone1( void ) {
00249     zone1Timeout.detach();
00250     zone1Interval = 0;
00251     compute1out = 0;
00252     zone1Timer.stop();
00253     zone1Timer.reset();
00254 }
00255 
00256 void SprinklerHandler::turnOffZone2( void ) {
00257     zone2Timeout.detach();
00258     zone2Interval = 0;
00259     compute2out = 0;
00260     zone2Timer.stop();
00261     zone2Timer.reset();
00262 }
00263 
00264 void SprinklerHandler::turnOffZone3( void ) {
00265     zone3Timeout.detach();
00266     zone3Interval = 0;
00267     compute3out = 0;
00268     zone3Timer.stop();
00269     zone3Timer.reset();
00270 }
00271 
00272 void SprinklerHandler::turnOffZone4( void ) {
00273     zone4Timeout.detach();
00274     zone4Interval = 0;
00275     compute4out = 0;
00276     zone4Timer.stop();
00277     zone4Timer.reset();
00278 }
00279 
00280