A sprinkler controller that takes HTTP command for zone and duration.
Dependencies: EthernetNetIf mbed HTTPServer
sprinkler_handler.cpp@1:91c2c52b4691, 2011-03-09 (annotated)
- 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?
User | Revision | Line number | New 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 |