Thanks to technologies like Ajax, todays powerfull webbrowsers, Cascadinf Stylesheets and frameworks like jQuery we can create awesome user-interfaces without running out of space or cycles on the Arduino platform. Take a minute to learn how this is done and enjoy the more user-friendly interfaces of your self-made gadgets in the future.
Examples https://www.danrl.de/danweb.php Fork it https://github.com/danrl/danweb
Serving JSON-formatted datasets is efficient and fast, all the eyecandy stuff can be done in the browser. In the meantime the Arduino sure has better things to do.
if (danweb_request("json")) { danweb_send_special_header(client, "application/json"); client.print("["); client.print("{ \"id\": 1, \"name\": \"hello\"},"); client.print("{ \"id\": 2, \"name\": \"world\"}"); client.print("]"); }
You can create your own API, simple calls are made via GET-request. E.g. http://example.com/apicall?bar will result in the webstate-variables being updated to request=apicall and argv=foo.
if (danweb_request("apicall")) { danweb_send_header(client); apicall_foo(webstate.argv); client.println("success!"); }
Of course simple file-serving is also possible.
if (danweb_request("jquery.js")) { danweb_send_special_header(client, "text/javascript"); danweb_send_file(client, "jquery.js"); }
Full source (see GitHub for latest version):
#include <SPI.h> #include <Ethernet.h> #include <SD.h> /* * ----------------------------------------------------------------------------- * Webserver danweb * ----------------------------------------------------------------------------- */ /* configuration */ #define DANWEB_MAC { 0x90, 0xa2, 0xda, 0x00, 0x91, 0x14 } #define DANWEB_IP4 { 94, 45, 236, 200 } #define DANWEB_PORT 80 #define DANWEB_SERBAUD 9600 #define DANWEB_PINSS 10 #define DANWEB_CSELECT 4 #define DANWEB_BUFFER 512 #define DANWEB_REQSIZE 32 #define DANWEB_ARGSIZE 64 Server server(DANWEB_PORT); struct danweb_webstate { char request[DANWEB_REQSIZE+1]; char argv[DANWEB_ARGSIZE+1]; }; struct danweb_webstate webstate; static int danweb_init () { Serial.begin(DANWEB_SERBAUD); Serial.println("danweb 0.1"); // start ethernet and server byte mac[] = DANWEB_MAC; byte ip4[] = DANWEB_IP4; Ethernet.begin(mac, ip4); server.begin(); // setting SS-pin as output pinMode(DANWEB_PINSS, OUTPUT); // init SD-Card Serial.print("SD init... "); if (SD.begin(DANWEB_CSELECT)) { Serial.println("done!"); } else { Serial.println("failed!"); return -1; } return 1; } static int danweb_readline_client (Client client, char *buf, int length) { if (!client.available()) return -1; int count = 0; char c; while ((c = client.read()) > 0) { if (c == '\r') continue; if (c == '\n') break; if (count >= length) break; buf[count++] = c; } buf[count] = 0; return count; } static int danweb_read_file (File file, char *buf, int length) { int count = 0; int16_t c; while ((c = file.read()) > 0) { buf[count++] = (char) c; if (count >= length) break; } buf[count] = 0; return count; } static int danweb_is_get_request (char *buf) { // a very simple test, but it works for now if (strstr(buf, "GET ") != 0) return 1; return 0; } static void danweb_parse_get_request (char *buffer) { // cut off the protocol version (strchr(&(buffer[5]), ' '))[0] = 0x0; // copy and truncate request strncpy(webstate.request, &(buffer[5]), DANWEB_REQSIZE); (strchr(webstate.request, '?'))[0] = 0x0; // arguments string strncpy(webstate.argv, strchr(&(buffer[5]), '?') +1, DANWEB_ARGSIZE); } static void danweb_send_header (Client client) { client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println(); } static void danweb_send_404 (Client client) { client.println("HTTP/1.1 404 Not Found"); client.println("Content-Type: text/html"); client.println(); client.println("404 Gone for good"); } static void danweb_send_special_header (Client client, char *contenttype) { client.println("HTTP/1.1 200 OK"); client.print("Content-Type: "); client.println(contenttype); client.println(); } static void danweb_send_file (Client client, char* path) { char fullpath[25]; strncpy(fullpath, "/danweb/", 24); strncat(fullpath, path, 24); if (SD.exists(fullpath)) { File f = SD.open(fullpath, FILE_READ); int16_t c; char buffer[DANWEB_BUFFER+1]; int i = 0; do { danweb_read_file(f, buffer, sizeof(buffer)); client.print(buffer); } while (strlen(buffer)); f.close(); } else { Serial.print("file not found: "); Serial.println(fullpath); } } static int danweb_idle (Client client) { if (!client) { delay(1); client.stop(); return 1; } char buffer[DANWEB_BUFFER]; while (client.connected() && client.available()) { danweb_readline_client(client, buffer, sizeof(buffer)); if (danweb_is_get_request(buffer)) { danweb_parse_get_request(buffer); Serial.print("request="); Serial.println(webstate.request); Serial.print("argv="); Serial.println(webstate.argv); } } return 0; } static int danweb_request (char *s) { if (strncmp(webstate.request, s, DANWEB_REQSIZE) == 0) return 1; return 0; } /* * ----------------------------------------------------------------------------- */ void setup() { /* ----- initialize webserver ----- */ if (!danweb_init()) return; /* -------------------------------- */ // your setup stuff goes here // serial line is already up /* -------------------------------- */ } void loop() { /* -------------------------------- */ // your loop stuff goes here // have fun /* -------------------------------- */ Client client = server.available(); if (danweb_idle(client)) return; /* -------------------------------- */ if (danweb_request("")) { danweb_send_header(client); danweb_send_file(client, "index.htm"); } else if (danweb_request("version")) { danweb_send_header(client); client.println("Version 0.1"); } else if (danweb_request("json")) { danweb_send_special_header(client, "application/json"); client.print("["); client.print("{ \"id\": 1, \"name\": \"hello\"},"); client.print("{ \"id\": 2, \"name\": \"world\"}"); client.print("]"); } else if (danweb_request("apicall")) { danweb_send_header(client); client.print("success! "); client.print(webstate.argv); /* some file serving */ } else if (danweb_request("style.css")) { danweb_send_special_header(client, "text/css"); danweb_send_file(client, "style.css"); } else if (danweb_request("jquery.js")) { danweb_send_special_header(client, "text/javascript"); danweb_send_file(client, "jquery.js"); } else { danweb_send_404(client); } client.stop(); }