A sprinkler controller that takes HTTP command for zone and duration.
Dependencies: EthernetNetIf mbed HTTPServer
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
Generated on Fri Jul 15 2022 01:20:29 by 1.7.2