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

Dependencies:   EthernetNetIf mbed HTTPServer

Committer:
dminear
Date:
Wed Mar 09 03:44:43 2011 +0000
Revision:
1:91c2c52b4691
Parent:
0:810ec1936452
Fixed constant setting of time via NTP.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dminear 0:810ec1936452 1 /*
dminear 0:810ec1936452 2 Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
dminear 0:810ec1936452 3
dminear 0:810ec1936452 4 Permission is hereby granted, free of charge, to any person obtaining a copy
dminear 0:810ec1936452 5 of this software and associated documentation files (the "Software"), to deal
dminear 0:810ec1936452 6 in the Software without restriction, including without limitation the rights
dminear 0:810ec1936452 7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
dminear 0:810ec1936452 8 copies of the Software, and to permit persons to whom the Software is
dminear 0:810ec1936452 9 furnished to do so, subject to the following conditions:
dminear 0:810ec1936452 10
dminear 0:810ec1936452 11 The above copyright notice and this permission notice shall be included in
dminear 0:810ec1936452 12 all copies or substantial portions of the Software.
dminear 0:810ec1936452 13
dminear 0:810ec1936452 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
dminear 0:810ec1936452 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
dminear 0:810ec1936452 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
dminear 0:810ec1936452 17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
dminear 0:810ec1936452 18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
dminear 0:810ec1936452 19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
dminear 0:810ec1936452 20 THE SOFTWARE.
dminear 0:810ec1936452 21 */
dminear 0:810ec1936452 22
dminear 0:810ec1936452 23 #include "sprinkler_handler.h"
dminear 0:810ec1936452 24 #include "share.h"
dminear 0:810ec1936452 25 #include <string>
dminear 0:810ec1936452 26 #include <cstring>
dminear 0:810ec1936452 27
dminear 0:810ec1936452 28 //#define __DEBUG
dminear 0:810ec1936452 29 #include "dbg/dbg.h"
dminear 0:810ec1936452 30
dminear 0:810ec1936452 31 // there are only 4 zones for this sprinkler controller
dminear 0:810ec1936452 32 Timer zone1Timer; // timers are used here, and they only go for about 30 minutes
dminear 0:810ec1936452 33 Timer zone2Timer; // so this is not good for hours...
dminear 0:810ec1936452 34 Timer zone3Timer;
dminear 0:810ec1936452 35 Timer zone4Timer;
dminear 0:810ec1936452 36 float zone1Interval;
dminear 0:810ec1936452 37 float zone2Interval;
dminear 0:810ec1936452 38 float zone3Interval;
dminear 0:810ec1936452 39 float zone4Interval;
dminear 0:810ec1936452 40 Timeout zone1Timeout;
dminear 0:810ec1936452 41 Timeout zone2Timeout;
dminear 0:810ec1936452 42 Timeout zone3Timeout;
dminear 0:810ec1936452 43 Timeout zone4Timeout;
dminear 0:810ec1936452 44
dminear 0:810ec1936452 45 SprinklerHandler::SprinklerHandler(const char* rootPath,
dminear 0:810ec1936452 46 const char* path,
dminear 0:810ec1936452 47 TCPSocket* pTCPSocket) : HTTPRequestHandler(rootPath,
dminear 0:810ec1936452 48 path,
dminear 0:810ec1936452 49 pTCPSocket)
dminear 0:810ec1936452 50 {
dminear 0:810ec1936452 51
dminear 0:810ec1936452 52 }
dminear 0:810ec1936452 53
dminear 0:810ec1936452 54 SprinklerHandler::~SprinklerHandler()
dminear 0:810ec1936452 55 {
dminear 0:810ec1936452 56 DBG("\r\nHandler destroyed\r\n");
dminear 0:810ec1936452 57 }
dminear 0:810ec1936452 58
dminear 0:810ec1936452 59 void SprinklerHandler::doGet()
dminear 0:810ec1936452 60 {
dminear 0:810ec1936452 61 char resp[300];
dminear 0:810ec1936452 62
dminear 0:810ec1936452 63 DBG("\r\nIn SprinklerHandler::doGet()\r\n");
dminear 0:810ec1936452 64 lanActivity();
dminear 0:810ec1936452 65 // just output the current timer values for each zone
dminear 0:810ec1936452 66 const char * match;
dminear 0:810ec1936452 67 if ((match = strstr( path().c_str(), "zone1")) > 0) {
dminear 0:810ec1936452 68 sprintf( resp, "zone1=%f\n", zone1Timer.read() );
dminear 0:810ec1936452 69 } else if ((match = strstr( path().c_str(), "zone2")) > 0 ) {
dminear 0:810ec1936452 70 sprintf( resp, "zone2=%f\n", zone2Timer.read() );
dminear 0:810ec1936452 71 } else if ((match = strstr( path().c_str(), "zone3")) > 0 ) {
dminear 0:810ec1936452 72 sprintf( resp, "zone3=%f\n", zone3Timer.read() );
dminear 0:810ec1936452 73 } else if ((match = strstr( path().c_str(), "zone4")) > 0 ) {
dminear 0:810ec1936452 74 sprintf( resp, "zone4=%f\n", zone4Timer.read() );
dminear 0:810ec1936452 75 } else { // assume they want all the status
dminear 0:810ec1936452 76 sprintf( resp, "zone1=%f\nzone2=%f\nzone3=%f\nzone4=%f\n",
dminear 0:810ec1936452 77 zone1Timer.read(), zone2Timer.read(), zone3Timer.read(), zone4Timer.read() );
dminear 0:810ec1936452 78 }
dminear 0:810ec1936452 79
dminear 0:810ec1936452 80 setContentLen( strlen(resp) );
dminear 0:810ec1936452 81 respHeaders()["Connection"] = "close";
dminear 0:810ec1936452 82 respHeaders()["Content-type"] = "text/html";
dminear 0:810ec1936452 83 writeData(resp, strlen(resp));
dminear 0:810ec1936452 84 DBG("\r\nExit SprinklerHandler::doGet()\r\n");
dminear 0:810ec1936452 85 }
dminear 0:810ec1936452 86
dminear 0:810ec1936452 87 void SprinklerHandler::doPost()
dminear 0:810ec1936452 88 {
dminear 0:810ec1936452 89 char data[128];
dminear 0:810ec1936452 90 string str = "POST path is " + path() + "\n";
dminear 0:810ec1936452 91 int maxlen = dataLen();
dminear 0:810ec1936452 92 if (maxlen > 127) { maxlen = 127; }
dminear 0:810ec1936452 93 int len = readData( data, maxlen );
dminear 0:810ec1936452 94 data[maxlen] = 0;
dminear 0:810ec1936452 95 string d = data;
dminear 0:810ec1936452 96 str += "and data is " + d + "\n";
dminear 0:810ec1936452 97
dminear 0:810ec1936452 98 lanActivity();
dminear 0:810ec1936452 99 // find out if it's a reset or start
dminear 0:810ec1936452 100 const char * match = strstr( path().c_str(), "reset");
dminear 0:810ec1936452 101 if (match > 0) { // must be reset
dminear 0:810ec1936452 102 // handle reset
dminear 0:810ec1936452 103 zone1Timer.stop();
dminear 0:810ec1936452 104 zone2Timer.stop();
dminear 0:810ec1936452 105 zone3Timer.stop();
dminear 0:810ec1936452 106 zone4Timer.stop();
dminear 0:810ec1936452 107 compute1out = 0;
dminear 0:810ec1936452 108 compute2out = 0;
dminear 0:810ec1936452 109 compute3out = 0;
dminear 0:810ec1936452 110 compute4out = 0;
dminear 0:810ec1936452 111 // cancel any pending timer interrupts
dminear 0:810ec1936452 112 zone1Timeout.detach();
dminear 0:810ec1936452 113 zone2Timeout.detach();
dminear 0:810ec1936452 114 zone3Timeout.detach();
dminear 0:810ec1936452 115 zone4Timeout.detach();
dminear 0:810ec1936452 116 zone1Interval = 0;
dminear 0:810ec1936452 117 zone2Interval = 0;
dminear 0:810ec1936452 118 zone3Interval = 0;
dminear 0:810ec1936452 119 zone4Interval = 0;
dminear 0:810ec1936452 120 str = "OK";
dminear 0:810ec1936452 121 DBG("\r\nreset called\r\n");
dminear 0:810ec1936452 122 } else if ((match = strstr( path().c_str(), "start")) > 0) { // must be start
dminear 0:810ec1936452 123 // get zone and duration from message - example: zone=1&duration=300
dminear 0:810ec1936452 124 map<string, string> params;
dminear 0:810ec1936452 125 char line[128];
dminear 0:810ec1936452 126 char key[128];
dminear 0:810ec1936452 127 char value[128];
dminear 0:810ec1936452 128 char * from = data;
dminear 0:810ec1936452 129 while( parsekv(&from, line, 128) > 0) //if == 0, it is an empty line = end of headers
dminear 0:810ec1936452 130 {
dminear 0:810ec1936452 131 int n = sscanf(line, "%[^=]=%[^\n]", key, value);
dminear 0:810ec1936452 132 if ( n == 2 )
dminear 0:810ec1936452 133 {
dminear 0:810ec1936452 134 DBG("Read params : %s : %s\r\n", key, value);
dminear 0:810ec1936452 135 params[key] = value;
dminear 0:810ec1936452 136 }
dminear 0:810ec1936452 137 }
dminear 0:810ec1936452 138 // get duration
dminear 0:810ec1936452 139 if (atoi(params["zone"].c_str()) < 1 || atoi(params["zone"].c_str()) > 4) {
dminear 0:810ec1936452 140 str = "unknown zone";
dminear 0:810ec1936452 141 } else {
dminear 0:810ec1936452 142 if (atoi(params["duration"].c_str()) <= 0) {
dminear 0:810ec1936452 143 str = "invalid duration";
dminear 0:810ec1936452 144 } else {
dminear 0:810ec1936452 145 int dur = atoi(params["duration"].c_str());
dminear 0:810ec1936452 146 switch (atoi(params["zone"].c_str())) {
dminear 0:810ec1936452 147 case 1:
dminear 0:810ec1936452 148 zone1Timer.reset();
dminear 0:810ec1936452 149 zone1Timer.start();
dminear 0:810ec1936452 150 compute1out = 1;
dminear 0:810ec1936452 151 zone1Interval = dur;
dminear 0:810ec1936452 152 zone1Timeout.attach( this, &SprinklerHandler::turnOffZone1, dur );
dminear 0:810ec1936452 153 break;
dminear 0:810ec1936452 154
dminear 0:810ec1936452 155 case 2:
dminear 0:810ec1936452 156 zone2Timer.reset();
dminear 0:810ec1936452 157 zone2Timer.start();
dminear 0:810ec1936452 158 compute2out = 1;
dminear 0:810ec1936452 159 zone2Interval = dur;
dminear 0:810ec1936452 160 zone2Timeout.attach( this, &SprinklerHandler::turnOffZone2, dur );
dminear 0:810ec1936452 161 break;
dminear 0:810ec1936452 162
dminear 0:810ec1936452 163 case 3:
dminear 0:810ec1936452 164 zone3Timer.reset();
dminear 0:810ec1936452 165 zone3Timer.start();
dminear 0:810ec1936452 166 compute3out = 1;
dminear 0:810ec1936452 167 zone3Interval = dur;
dminear 0:810ec1936452 168 zone3Timeout.attach( this, &SprinklerHandler::turnOffZone3, dur );
dminear 0:810ec1936452 169 break;
dminear 0:810ec1936452 170
dminear 0:810ec1936452 171 case 4:
dminear 0:810ec1936452 172 zone4Timer.reset();
dminear 0:810ec1936452 173 zone4Timer.start();
dminear 0:810ec1936452 174 compute4out = 1;
dminear 0:810ec1936452 175 zone4Interval = dur;
dminear 0:810ec1936452 176 zone4Timeout.attach( this, &SprinklerHandler::turnOffZone4, dur );
dminear 0:810ec1936452 177 break;
dminear 0:810ec1936452 178
dminear 0:810ec1936452 179 default:
dminear 0:810ec1936452 180 str = "bad zone in case statement";
dminear 0:810ec1936452 181 break;
dminear 0:810ec1936452 182 }
dminear 0:810ec1936452 183 }
dminear 0:810ec1936452 184 }
dminear 0:810ec1936452 185
dminear 0:810ec1936452 186 DBG("\r\nstart called\r\n");
dminear 0:810ec1936452 187 }
dminear 0:810ec1936452 188
dminear 0:810ec1936452 189 const char * resp = str.c_str();
dminear 0:810ec1936452 190 setContentLen( strlen(resp) );
dminear 0:810ec1936452 191 respHeaders()["Content-type"] = "text/html";
dminear 0:810ec1936452 192 respHeaders()["Connection"] = "close";
dminear 0:810ec1936452 193 writeData(resp, strlen(resp));
dminear 0:810ec1936452 194 DBG("\r\nExit SprinklerHandler::doPost()\r\n");
dminear 0:810ec1936452 195 }
dminear 0:810ec1936452 196
dminear 0:810ec1936452 197 // taken from the HTTP parsing code
dminear 0:810ec1936452 198 int SprinklerHandler::parsekv( char **from, char *to, int max ) {
dminear 0:810ec1936452 199 /*
dminear 0:810ec1936452 200 * look for & or \n and return key=value line
dminear 0:810ec1936452 201 */
dminear 0:810ec1936452 202 char *end;
dminear 0:810ec1936452 203 int retval = 0;
dminear 0:810ec1936452 204
dminear 0:810ec1936452 205 end = strstr( *from, "&" );
dminear 0:810ec1936452 206 if (end) {
dminear 0:810ec1936452 207 int len = (end - *from);
dminear 0:810ec1936452 208 strncpy( to, *from, len);
dminear 0:810ec1936452 209 to[len] = 0;
dminear 0:810ec1936452 210 *from += len + 1;
dminear 0:810ec1936452 211 DBG("parsekv sending back %s\r\n", to);
dminear 0:810ec1936452 212 retval = 1;
dminear 0:810ec1936452 213 } else {
dminear 0:810ec1936452 214 // maybe this was the last parameter
dminear 0:810ec1936452 215 if (strstr(*from, "=")) {
dminear 0:810ec1936452 216 strncpy( to, *from, strlen(*from));
dminear 0:810ec1936452 217 to[strlen(*from)] = 0;
dminear 0:810ec1936452 218 *from += strlen(*from);
dminear 0:810ec1936452 219 DBG("parsekv sending back %s\r\n", to);
dminear 0:810ec1936452 220 retval = 1;
dminear 0:810ec1936452 221 }
dminear 0:810ec1936452 222 // nope, nothing left, just fall through and return 0
dminear 0:810ec1936452 223 }
dminear 0:810ec1936452 224 return retval;
dminear 0:810ec1936452 225 }
dminear 0:810ec1936452 226
dminear 0:810ec1936452 227 void SprinklerHandler::doHead()
dminear 0:810ec1936452 228 {
dminear 0:810ec1936452 229
dminear 0:810ec1936452 230 }
dminear 0:810ec1936452 231
dminear 0:810ec1936452 232 void SprinklerHandler::onReadable() //Data has been read
dminear 0:810ec1936452 233 {
dminear 0:810ec1936452 234
dminear 0:810ec1936452 235 }
dminear 0:810ec1936452 236
dminear 0:810ec1936452 237 void SprinklerHandler::onWriteable() //Data has been written & buf is free
dminear 0:810ec1936452 238 {
dminear 0:810ec1936452 239 DBG("\r\nSimpleHandler::onWriteable() event\r\n");
dminear 0:810ec1936452 240 close(); //Data written, we can close the connection
dminear 0:810ec1936452 241 }
dminear 0:810ec1936452 242
dminear 0:810ec1936452 243 void SprinklerHandler::onClose() //Connection is closing
dminear 0:810ec1936452 244 {
dminear 0:810ec1936452 245 //Nothing to do
dminear 0:810ec1936452 246 }
dminear 0:810ec1936452 247
dminear 0:810ec1936452 248 void SprinklerHandler::turnOffZone1( void ) {
dminear 0:810ec1936452 249 zone1Timeout.detach();
dminear 0:810ec1936452 250 zone1Interval = 0;
dminear 0:810ec1936452 251 compute1out = 0;
dminear 0:810ec1936452 252 zone1Timer.stop();
dminear 0:810ec1936452 253 zone1Timer.reset();
dminear 0:810ec1936452 254 }
dminear 0:810ec1936452 255
dminear 0:810ec1936452 256 void SprinklerHandler::turnOffZone2( void ) {
dminear 0:810ec1936452 257 zone2Timeout.detach();
dminear 0:810ec1936452 258 zone2Interval = 0;
dminear 0:810ec1936452 259 compute2out = 0;
dminear 0:810ec1936452 260 zone2Timer.stop();
dminear 0:810ec1936452 261 zone2Timer.reset();
dminear 0:810ec1936452 262 }
dminear 0:810ec1936452 263
dminear 0:810ec1936452 264 void SprinklerHandler::turnOffZone3( void ) {
dminear 0:810ec1936452 265 zone3Timeout.detach();
dminear 0:810ec1936452 266 zone3Interval = 0;
dminear 0:810ec1936452 267 compute3out = 0;
dminear 0:810ec1936452 268 zone3Timer.stop();
dminear 0:810ec1936452 269 zone3Timer.reset();
dminear 0:810ec1936452 270 }
dminear 0:810ec1936452 271
dminear 0:810ec1936452 272 void SprinklerHandler::turnOffZone4( void ) {
dminear 0:810ec1936452 273 zone4Timeout.detach();
dminear 0:810ec1936452 274 zone4Interval = 0;
dminear 0:810ec1936452 275 compute4out = 0;
dminear 0:810ec1936452 276 zone4Timer.stop();
dminear 0:810ec1936452 277 zone4Timer.reset();
dminear 0:810ec1936452 278 }
dminear 0:810ec1936452 279
dminear 0:810ec1936452 280