A remote timer, equipped with a scheduling Web interface, controls a "DigitalOut".
Dependencies: Timezone NTPClient
WebTimer
The WebTimer is an Mbed device enabling to remotely control a DigitalOut. It has a "calendar-like" user interface to edit the schedule - a table you can click on (or tap on a touch-screen device).
The program was ported to Mbed from the Tuxgraphics site. Thank you Guido for sharing!
- When starting, it will print it's IP address over the USB serial link to the terminal screen. However, you can set a different static IP address if you modify the code in the
main.cpp
. - To connect to the WebTimer, type the IP address into the web browser edit box and hit
ENTER
. - When a cell is green then the timer keeps it's output
ON
during that period of time. If a cell is not green it means the output isOFF
.
- To select or deselect multiple cells you can click (keep down the button) and move the mouse over more cells.
- The smallest time interval on this 24h timer is 15minutes.
- To save the changes type in the password and hit
ENTER
or click on theSave
button. - The default password is "secret". But you can change it by editing the source code in
main.cpp
.
websrv_help_functions.c@0:f78e57015038, 2020-11-11 (annotated)
- Committer:
- hudakz
- Date:
- Wed Nov 11 16:56:02 2020 +0000
- Revision:
- 0:f78e57015038
A timer to control a DigitalOut equipped with Web interface for scheduling.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
hudakz | 0:f78e57015038 | 1 | /********************************************* |
hudakz | 0:f78e57015038 | 2 | * vim:sw=8:ts=8:si:et |
hudakz | 0:f78e57015038 | 3 | * To use the above modeline in vim you must have "set modeline" in your .vimrc |
hudakz | 0:f78e57015038 | 4 | * Author: Guido Socher |
hudakz | 0:f78e57015038 | 5 | * Copyright:LGPL V2 |
hudakz | 0:f78e57015038 | 6 | * See http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html |
hudakz | 0:f78e57015038 | 7 | * |
hudakz | 0:f78e57015038 | 8 | * Some common utilities needed for IP and web applications. |
hudakz | 0:f78e57015038 | 9 | * The defines below are controlled via ip_config.h. By choosing |
hudakz | 0:f78e57015038 | 10 | * the right defines for your application in ip_config.h you can |
hudakz | 0:f78e57015038 | 11 | * significantly reduce the size of the resulting code. |
hudakz | 0:f78e57015038 | 12 | *********************************************/ |
hudakz | 0:f78e57015038 | 13 | #include <stdlib.h> |
hudakz | 0:f78e57015038 | 14 | #include <stdio.h> |
hudakz | 0:f78e57015038 | 15 | #include <string.h> |
hudakz | 0:f78e57015038 | 16 | #include <ctype.h> |
hudakz | 0:f78e57015038 | 17 | #include "websrv_help_functions.h" |
hudakz | 0:f78e57015038 | 18 | |
hudakz | 0:f78e57015038 | 19 | #ifdef FROMDECODE_websrv_help |
hudakz | 0:f78e57015038 | 20 | // search for a string of the form key=value in |
hudakz | 0:f78e57015038 | 21 | // a string that looks like q?xyz=abc&uvw=defgh HTTP/1.1\r\n |
hudakz | 0:f78e57015038 | 22 | // The returned value is stored in strbuf. You must allocate |
hudakz | 0:f78e57015038 | 23 | // enough storage for strbuf, maxlen is the size of strbuf. |
hudakz | 0:f78e57015038 | 24 | |
hudakz | 0:f78e57015038 | 25 | // I.e the value it is declared with: strbuf[5]-> maxlen=5 |
hudakz | 0:f78e57015038 | 26 | uint8_t find_key_val(char* str, char* strbuf, uint8_t maxlen, char* key) |
hudakz | 0:f78e57015038 | 27 | { |
hudakz | 0:f78e57015038 | 28 | uint8_t found = 0; |
hudakz | 0:f78e57015038 | 29 | uint8_t i = 0; |
hudakz | 0:f78e57015038 | 30 | char* kp; |
hudakz | 0:f78e57015038 | 31 | kp = key; |
hudakz | 0:f78e57015038 | 32 | while (*str && *str != ' ' && *str != '\r' && found == 0) { |
hudakz | 0:f78e57015038 | 33 | if (*str == *kp) { |
hudakz | 0:f78e57015038 | 34 | |
hudakz | 0:f78e57015038 | 35 | // At the beginning of the key we must check |
hudakz | 0:f78e57015038 | 36 | // if this is the start of the key otherwise we will |
hudakz | 0:f78e57015038 | 37 | // match on 'foobar' when only looking for 'bar', by andras tucsni |
hudakz | 0:f78e57015038 | 38 | if (kp == key && !(*(str - 1) == '?' || *(str - 1) == '&')) |
hudakz | 0:f78e57015038 | 39 | goto NEXT; |
hudakz | 0:f78e57015038 | 40 | kp++; |
hudakz | 0:f78e57015038 | 41 | if (*kp == '\0') { |
hudakz | 0:f78e57015038 | 42 | str++; |
hudakz | 0:f78e57015038 | 43 | kp = key; |
hudakz | 0:f78e57015038 | 44 | if (*str == '=') { |
hudakz | 0:f78e57015038 | 45 | found = 1; |
hudakz | 0:f78e57015038 | 46 | } |
hudakz | 0:f78e57015038 | 47 | } |
hudakz | 0:f78e57015038 | 48 | } |
hudakz | 0:f78e57015038 | 49 | else { |
hudakz | 0:f78e57015038 | 50 | kp = key; |
hudakz | 0:f78e57015038 | 51 | } |
hudakz | 0:f78e57015038 | 52 | |
hudakz | 0:f78e57015038 | 53 | NEXT: |
hudakz | 0:f78e57015038 | 54 | str++; |
hudakz | 0:f78e57015038 | 55 | } |
hudakz | 0:f78e57015038 | 56 | |
hudakz | 0:f78e57015038 | 57 | if (found == 1) { |
hudakz | 0:f78e57015038 | 58 | |
hudakz | 0:f78e57015038 | 59 | // copy the value to a buffer and terminate it with '\0' |
hudakz | 0:f78e57015038 | 60 | while (*str && *str != ' ' && *str != '\r' && *str != '&' && i < maxlen - 1) { |
hudakz | 0:f78e57015038 | 61 | *strbuf = *str; |
hudakz | 0:f78e57015038 | 62 | i++; |
hudakz | 0:f78e57015038 | 63 | str++; |
hudakz | 0:f78e57015038 | 64 | strbuf++; |
hudakz | 0:f78e57015038 | 65 | } |
hudakz | 0:f78e57015038 | 66 | |
hudakz | 0:f78e57015038 | 67 | *strbuf = '\0'; |
hudakz | 0:f78e57015038 | 68 | } |
hudakz | 0:f78e57015038 | 69 | |
hudakz | 0:f78e57015038 | 70 | // return 1 if found (the string in strbuf might still be an empty string) |
hudakz | 0:f78e57015038 | 71 | // otherwise return 0 |
hudakz | 0:f78e57015038 | 72 | return(found); |
hudakz | 0:f78e57015038 | 73 | } |
hudakz | 0:f78e57015038 | 74 | |
hudakz | 0:f78e57015038 | 75 | // convert a single hex digit character to its integer value |
hudakz | 0:f78e57015038 | 76 | unsigned char h2int(char c) |
hudakz | 0:f78e57015038 | 77 | { |
hudakz | 0:f78e57015038 | 78 | if (c >= '0' && c <= '9') { |
hudakz | 0:f78e57015038 | 79 | return((unsigned char)c - '0'); |
hudakz | 0:f78e57015038 | 80 | } |
hudakz | 0:f78e57015038 | 81 | |
hudakz | 0:f78e57015038 | 82 | if (c >= 'a' && c <= 'f') { |
hudakz | 0:f78e57015038 | 83 | return((unsigned char)c - 'a' + 10); |
hudakz | 0:f78e57015038 | 84 | } |
hudakz | 0:f78e57015038 | 85 | |
hudakz | 0:f78e57015038 | 86 | if (c >= 'A' && c <= 'F') { |
hudakz | 0:f78e57015038 | 87 | return((unsigned char)c - 'A' + 10); |
hudakz | 0:f78e57015038 | 88 | } |
hudakz | 0:f78e57015038 | 89 | |
hudakz | 0:f78e57015038 | 90 | return(0); |
hudakz | 0:f78e57015038 | 91 | } |
hudakz | 0:f78e57015038 | 92 | |
hudakz | 0:f78e57015038 | 93 | // decode a url string e.g "hello%20joe" or "hello+joe" becomes "hello joe" |
hudakz | 0:f78e57015038 | 94 | void urldecode(char* urlbuf) |
hudakz | 0:f78e57015038 | 95 | { |
hudakz | 0:f78e57015038 | 96 | char c; |
hudakz | 0:f78e57015038 | 97 | char* dst; |
hudakz | 0:f78e57015038 | 98 | dst = urlbuf; |
hudakz | 0:f78e57015038 | 99 | while ((c = *urlbuf)) { |
hudakz | 0:f78e57015038 | 100 | if (c == '+') |
hudakz | 0:f78e57015038 | 101 | c = ' '; |
hudakz | 0:f78e57015038 | 102 | if (c == '%') { |
hudakz | 0:f78e57015038 | 103 | urlbuf++; |
hudakz | 0:f78e57015038 | 104 | c = *urlbuf; |
hudakz | 0:f78e57015038 | 105 | urlbuf++; |
hudakz | 0:f78e57015038 | 106 | c = (h2int(c) << 4) | h2int(*urlbuf); |
hudakz | 0:f78e57015038 | 107 | } |
hudakz | 0:f78e57015038 | 108 | |
hudakz | 0:f78e57015038 | 109 | *dst = c; |
hudakz | 0:f78e57015038 | 110 | dst++; |
hudakz | 0:f78e57015038 | 111 | urlbuf++; |
hudakz | 0:f78e57015038 | 112 | } |
hudakz | 0:f78e57015038 | 113 | |
hudakz | 0:f78e57015038 | 114 | *dst = '\0'; |
hudakz | 0:f78e57015038 | 115 | } |
hudakz | 0:f78e57015038 | 116 | #endif // FROMDECODE_websrv_help |
hudakz | 0:f78e57015038 | 117 | |
hudakz | 0:f78e57015038 | 118 | #ifdef URLENCODE_websrv_help |
hudakz | 0:f78e57015038 | 119 | // convert a single character to a 2 digit hex str |
hudakz | 0:f78e57015038 | 120 | |
hudakz | 0:f78e57015038 | 121 | // a terminating '\0' is added |
hudakz | 0:f78e57015038 | 122 | void int2h(char c, char* hstr) |
hudakz | 0:f78e57015038 | 123 | { |
hudakz | 0:f78e57015038 | 124 | hstr[1] = (c & 0xf) + '0'; |
hudakz | 0:f78e57015038 | 125 | if ((c & 0xf) > 9) { |
hudakz | 0:f78e57015038 | 126 | hstr[1] = (c & 0xf) - 10 + 'a'; |
hudakz | 0:f78e57015038 | 127 | } |
hudakz | 0:f78e57015038 | 128 | |
hudakz | 0:f78e57015038 | 129 | c = (c >> 4) & 0xf; |
hudakz | 0:f78e57015038 | 130 | hstr[0] = c + '0'; |
hudakz | 0:f78e57015038 | 131 | if (c > 9) { |
hudakz | 0:f78e57015038 | 132 | hstr[0] = c - 10 + 'a'; |
hudakz | 0:f78e57015038 | 133 | } |
hudakz | 0:f78e57015038 | 134 | |
hudakz | 0:f78e57015038 | 135 | hstr[2] = '\0'; |
hudakz | 0:f78e57015038 | 136 | } |
hudakz | 0:f78e57015038 | 137 | |
hudakz | 0:f78e57015038 | 138 | // There must be enough space in urlbuf. In the worst case that would be |
hudakz | 0:f78e57015038 | 139 | |
hudakz | 0:f78e57015038 | 140 | // 3 times the length of str |
hudakz | 0:f78e57015038 | 141 | void urlencode(const char* str, char* urlbuf) |
hudakz | 0:f78e57015038 | 142 | { |
hudakz | 0:f78e57015038 | 143 | char c; |
hudakz | 0:f78e57015038 | 144 | while ((c = *str)) { |
hudakz | 0:f78e57015038 | 145 | if (c == ' ' || isalnum(c)) { |
hudakz | 0:f78e57015038 | 146 | if (c == ' ') { |
hudakz | 0:f78e57015038 | 147 | c = '+'; |
hudakz | 0:f78e57015038 | 148 | } |
hudakz | 0:f78e57015038 | 149 | |
hudakz | 0:f78e57015038 | 150 | *urlbuf = c; |
hudakz | 0:f78e57015038 | 151 | str++; |
hudakz | 0:f78e57015038 | 152 | urlbuf++; |
hudakz | 0:f78e57015038 | 153 | continue; |
hudakz | 0:f78e57015038 | 154 | } |
hudakz | 0:f78e57015038 | 155 | |
hudakz | 0:f78e57015038 | 156 | *urlbuf = '%'; |
hudakz | 0:f78e57015038 | 157 | urlbuf++; |
hudakz | 0:f78e57015038 | 158 | int2h(c, urlbuf); |
hudakz | 0:f78e57015038 | 159 | urlbuf++; |
hudakz | 0:f78e57015038 | 160 | urlbuf++; |
hudakz | 0:f78e57015038 | 161 | str++; |
hudakz | 0:f78e57015038 | 162 | } |
hudakz | 0:f78e57015038 | 163 | |
hudakz | 0:f78e57015038 | 164 | *urlbuf = '\0'; |
hudakz | 0:f78e57015038 | 165 | } |
hudakz | 0:f78e57015038 | 166 | #endif // URLENCODE_websrv_help |
hudakz | 0:f78e57015038 | 167 | |
hudakz | 0:f78e57015038 | 168 | // parse a string that is an IP address and extract the IP to ip_byte_str |
hudakz | 0:f78e57015038 | 169 | uint8_t parse_ip(uint8_t* ip_byte_str, const char* str) |
hudakz | 0:f78e57015038 | 170 | { |
hudakz | 0:f78e57015038 | 171 | char strbuf[4]; |
hudakz | 0:f78e57015038 | 172 | uint8_t bufpos = 0; |
hudakz | 0:f78e57015038 | 173 | uint8_t i = 0; |
hudakz | 0:f78e57015038 | 174 | while (i < 4) { |
hudakz | 0:f78e57015038 | 175 | ip_byte_str[i] = 0; |
hudakz | 0:f78e57015038 | 176 | i++; |
hudakz | 0:f78e57015038 | 177 | } |
hudakz | 0:f78e57015038 | 178 | |
hudakz | 0:f78e57015038 | 179 | i = 0; |
hudakz | 0:f78e57015038 | 180 | while (*str && i < 4) { |
hudakz | 0:f78e57015038 | 181 | |
hudakz | 0:f78e57015038 | 182 | // if a number then start |
hudakz | 0:f78e57015038 | 183 | if (bufpos < 3 && isdigit(*str)) { |
hudakz | 0:f78e57015038 | 184 | strbuf[bufpos] = *str; // copy |
hudakz | 0:f78e57015038 | 185 | bufpos++; |
hudakz | 0:f78e57015038 | 186 | } |
hudakz | 0:f78e57015038 | 187 | |
hudakz | 0:f78e57015038 | 188 | if (bufpos && *str == '.') { |
hudakz | 0:f78e57015038 | 189 | strbuf[bufpos] = '\0'; |
hudakz | 0:f78e57015038 | 190 | ip_byte_str[i] = (atoi(strbuf) & 0xff); |
hudakz | 0:f78e57015038 | 191 | i++; |
hudakz | 0:f78e57015038 | 192 | bufpos = 0; |
hudakz | 0:f78e57015038 | 193 | } |
hudakz | 0:f78e57015038 | 194 | |
hudakz | 0:f78e57015038 | 195 | str++; |
hudakz | 0:f78e57015038 | 196 | } |
hudakz | 0:f78e57015038 | 197 | |
hudakz | 0:f78e57015038 | 198 | if (i == 3) { |
hudakz | 0:f78e57015038 | 199 | |
hudakz | 0:f78e57015038 | 200 | // must have read the first componets of the IP |
hudakz | 0:f78e57015038 | 201 | strbuf[bufpos] = '\0'; |
hudakz | 0:f78e57015038 | 202 | ip_byte_str[i] = (atoi(strbuf) & 0xff); |
hudakz | 0:f78e57015038 | 203 | return(0); |
hudakz | 0:f78e57015038 | 204 | } |
hudakz | 0:f78e57015038 | 205 | |
hudakz | 0:f78e57015038 | 206 | return(1); |
hudakz | 0:f78e57015038 | 207 | } |
hudakz | 0:f78e57015038 | 208 | |
hudakz | 0:f78e57015038 | 209 | // take a byte string and convert it to a human readable display string (base is 10 for ip and 16 for mac addr), len is 4 for IP addr and 6 for mac. |
hudakz | 0:f78e57015038 | 210 | void mk_net_str(char* resultstr, uint8_t* ip_byte_str, uint8_t len, char separator, uint8_t base) |
hudakz | 0:f78e57015038 | 211 | { |
hudakz | 0:f78e57015038 | 212 | uint8_t i = 0; |
hudakz | 0:f78e57015038 | 213 | uint8_t j = 0; |
hudakz | 0:f78e57015038 | 214 | while (i < len) { |
hudakz | 0:f78e57015038 | 215 | sprintf(resultstr, base == 10 ? "%i" : "%x", (int)ip_byte_str[i]); |
hudakz | 0:f78e57015038 | 216 | |
hudakz | 0:f78e57015038 | 217 | // search end of str: |
hudakz | 0:f78e57015038 | 218 | while (resultstr[j]) { |
hudakz | 0:f78e57015038 | 219 | j++; |
hudakz | 0:f78e57015038 | 220 | } |
hudakz | 0:f78e57015038 | 221 | |
hudakz | 0:f78e57015038 | 222 | if (separator) { |
hudakz | 0:f78e57015038 | 223 | |
hudakz | 0:f78e57015038 | 224 | // no separator, separator==NULL is as well possible, suggested by andras tucsni |
hudakz | 0:f78e57015038 | 225 | resultstr[j] = separator; |
hudakz | 0:f78e57015038 | 226 | j++; |
hudakz | 0:f78e57015038 | 227 | } |
hudakz | 0:f78e57015038 | 228 | |
hudakz | 0:f78e57015038 | 229 | i++; |
hudakz | 0:f78e57015038 | 230 | } |
hudakz | 0:f78e57015038 | 231 | |
hudakz | 0:f78e57015038 | 232 | j--; |
hudakz | 0:f78e57015038 | 233 | resultstr[j] = '\0'; |
hudakz | 0:f78e57015038 | 234 | } |