plotly interface based on ardunio sample code

Dependents:   Plotly_HelloWorld

Library for plotting a simple x/y scatter chart on the plot.ly website.

See plotly_HelloWorld for sample usage.

Revision:
4:33006c37c633
Parent:
3:967be3d46701
Child:
5:fc8eefeb301b
--- a/plotly.cpp	Fri Jul 11 08:08:06 2014 +0000
+++ b/plotly.cpp	Fri Jul 11 10:10:16 2014 +0000
@@ -4,23 +4,22 @@
 #define plotlyURL "plot.ly"
 #define dataURL "arduino.plot.ly"
 
-plotly::plotly(char *username, char *api_key, char* stream_tokens[], char *filename, int nTraces)
+plotly::plotly(char *username, char *api_key, char* stream_token, char *filename)
 {
-    log_level = 0;  // 0 = Debugging, 1 = Informational, 2 = Status, 3 = Errors, 4 = Quiet (// Serial Off)
+    log_level = 3;  // 0 = Debugging, 1 = Informational, 2 = Status, 3 = Errors, 4 = Quiet (// Serial Off)
     dry_run = false;
     username_ = username;
     api_key_ = api_key;
-    stream_tokens_ = stream_tokens;
+    stream_token_ = stream_token;
     filename_ = filename;
-    nTraces_ = nTraces;
     maxpoints = 30;
-    fibonacci_ = 1;
     world_readable = true;
-    convertTimestamp = true;
+    convertTimestamp = false;
     timezone = "America/Montreal";
     fileopt = "overwrite";
 
     socket = NULL;
+
     initalised = false;
 }
 
@@ -28,13 +27,16 @@
 plotly::~plotly()
 {
     closeStream();
+
 }
 
+
 bool plotly::init()
 {
 
     //
-    //  Validate a stream with a REST post to plotly
+    //  Create plot with a REST post to plotly
+    //  See the clientresp section of https://plot.ly/rest/ for details
     //
     if(dry_run && log_level < 3) {
         fprintf(stderr,"... This is a dry run, we are not connecting to plotly's servers...\n");
@@ -42,13 +44,18 @@
         fprintf(stderr,"... Attempting to connect to plotly's REST servers\n");
     }
 
-//    socket.set_blocking(false);
-
     if (!dry_run) {
+        int pause = 1;
         socket = new TCPSocketConnection();
         while (socket->connect(plotlyURL, 80) < 0) {
+            if (pause > 30) {
+                fprintf(stderr,"Failed to connect. :-(\n");
+                delete socket;
+                return false;
+            }
             fprintf(stderr,"... Couldn\'t connect to plotly's REST servers... trying again!\n");
-            wait(1);
+            wait(pause);
+            pause *= 2;
         }
     }
 
@@ -60,93 +67,24 @@
     print_("Host: 107.21.214.199\r\n");
     print_("User-Agent: Arduino/0.5.1\r\n");
     print_("plotly-streamtoken: ");
-    print_(stream_tokens_[0]);
-    print_("\r\n");
+    print_(stream_token_);
+    printNetTerminator_();
 
     print_("Content-Length: ");
-    int contentLength = 126 + len_(username_) + len_(fileopt) + nTraces_*(87+len_(maxpoints)) + (nTraces_-1)*2 + len_(filename_);
-    if(world_readable) {
-        contentLength += 4;
-    } else {
-        contentLength += 5;
-    }
-    // contentLength =
-    //   44  // first part of querystring below
-    // + len_(username)  // upper bound on username length
-    // + 5   // &key=
-    // + 10  // api_key length
-    // + 7  // &args=[...
-    // + nTraces*(87+len(maxpoints)) // len({\"y\": [], \"x\": [], \"type\": \"scatter\", \"stream\": {\"token\": \") + 10 + len(\", "maxpoints": )+len(maxpoints)+len(}})
-    // + (nTraces-1)*2 // ", " in between trace objects
-    // + 22  // ]&kwargs={\"fileopt\": \"
-    // + len_(fileopt)
-    // + 16  // \", \"filename\": \"
-    // + len_(filename)
-    // + 21 // ", "world_readable":
-    // + 4 if world_readable, 5 otherwise
-    // + 1   // closing }
-    //------
-    // 126 + len_(username) + len_(fileopt) + nTraces*(86+len(maxpoints)) + (nTraces-1)*2 + len_(filename)
-    //
-    // Terminate headers with new lines
 
-
-// big buffer method to generate the string so that length can be measured directly.
-
-
-//    fprintf(stderr,"AutoVersion:\n");
+    // calculate the length of the packet payload and store it in the big buffer.
     int lineLen = snprintf(buffer,k_bufferSize,"version=2.3&origin=plot&platform=arduino&un=%s&key=%s&args=[",username_,api_key_);
-    for(int i=0; i<nTraces_; i++) {
-        lineLen += snprintf((buffer+lineLen),k_bufferSize-lineLen,"{\"y\": [], \"x\": [], \"type\": \"scatter\", \"stream\": {\"token\": \"%s\", \"maxpoints\": %d}}%s",stream_tokens_[i],maxpoints,((nTraces_ > 1) && (i != nTraces_-1))?", ":"");
-    }
+    lineLen += snprintf((buffer+lineLen),k_bufferSize-lineLen,"{\"y\": [], \"x\": [], \"type\": \"scatter\", \"stream\": {\"token\": \"%s\", \"maxpoints\": %d}}",stream_token_,maxpoints);
     lineLen += snprintf((buffer+lineLen),k_bufferSize-lineLen,"]&kwargs={\"fileopt\": \"%s\", \"filename\": \"%s\", \"world_readable\": %s}",fileopt,filename_,world_readable?"true":"false");
 
-//    fprintf(stderr,buffer);
-//    fprintf(stderr,"\nLen = %d",lineLen);
+    print_(lineLen);
 
-    print_(lineLen);
-    print_("\r\n\r\n");
-    
-    lineLen = snprintf(buffer,k_bufferSize,"version=2.3&origin=plot&platform=arduino&un=%s&key=%s&args=[",username_,api_key_);
-    for(int i=0; i<nTraces_; i++) {
-        lineLen += snprintf((buffer+lineLen),k_bufferSize-lineLen,"{\"y\": [], \"x\": [], \"type\": \"scatter\", \"stream\": {\"token\": \"%s\", \"maxpoints\": %d}}%s",stream_tokens_[i],maxpoints,((nTraces_ > 1) && (i != nTraces_-1))?", ":"");
-    }
-    lineLen += snprintf((buffer+lineLen),k_bufferSize-lineLen,"]&kwargs={\"fileopt\": \"%s\", \"filename\": \"%s\", \"world_readable\": %s}",fileopt,filename_,world_readable?"true":"false");
+    printNetTerminator_();
+    printNetTerminator_();
+
     sendFormatedText(buffer,lineLen);
-    
-    print_("\r\n");
-/*            
-    // Start printing querystring body
-    print_("version=2.2&origin=plot&platform=arduino&un=");
-    print_(username_);
-    print_("&key=");
-    print_(api_key_);
-    print_("&args=[");
-    // print a trace for each token supplied
-    for(int i=0; i<nTraces_; i++) {
-        print_("{\"y\": [], \"x\": [], \"type\": \"scatter\", \"stream\": {\"token\": \"");
-        print_(stream_tokens_[i]);
-        print_("\", \"maxpoints\": ");
-        print_(maxpoints);
-        print_("}}");
-        if(nTraces_ > 1 && i != nTraces_-1) {
-            print_(", ");
-        }
-    }
-    print_("]&kwargs={\"fileopt\": \"");
-    print_(fileopt);
-    print_("\", \"filename\": \"");
-    print_(filename_);
-    print_("\", \"world_readable\": ");
-    if(world_readable) {
-        print_("true");
-    } else {
-        print_("false");
-    }
-    print_("}");
-    // final newline to terminate the POST
-    print_("\r\n");
-*/
+
+    printNetTerminator_();
 
     //
     // Wait for a response
@@ -188,7 +126,7 @@
                     // by comparing characters as they roll in
                     //
 
-                    if(asgCnt == len_(allStreamsGo) && !proceed) {
+                    if(asgCnt == strlen(allStreamsGo) && !proceed) {
                         proceed = true;
                     } else if(allStreamsGo[asgCnt]==c) {
                         asgCnt += 1;
@@ -205,15 +143,15 @@
                     //
 
                     if(log_level < 3) {
-                        if(url[urlCnt]==c && urlCnt < len_(url)) {
+                        if(url[urlCnt]==c && urlCnt < strlen(url)) {
                             urlCnt += 1;
-                        } else if(urlCnt > 0 && urlCnt < len_(url)) {
+                        } else if(urlCnt > 0 && urlCnt < strlen(url)) {
                             // Reset counter
                             urlCnt = 0;
                         }
-                        if(urlCnt == len_(url) && fidCnt < 4 && !fidMatched) {
+                        if(urlCnt == strlen(url) && fidCnt < 4 && !fidMatched) {
                             // We've counted through the url, start counting through the username
-                            if(usernameCnt < len_(username_)+2) {
+                            if(usernameCnt < strlen(username_)+2) {
                                 usernameCnt += 1;
                             } else {
                                 // the url ends with "
@@ -244,27 +182,28 @@
             fprintf(stderr,username_);
             fprintf(stderr,"/");
             for(int i=0; i<fidCnt; i++) {
-                fprintf(stderr,"%d ",fid[i]);
+                fprintf(stderr,"%c",fid[i]);
             }
             fprintf(stderr,"\n");
         }
     }
 
     if (proceed || dry_run) {
-      initalised = true;
+        initalised = true;
     }
     if (socket) {
-      delete socket;
-      socket=NULL;
-      }
+        delete socket;
+        socket=NULL;
+    }
     return initalised;
 }
 
-void plotly::openStream()
+bool plotly::openStream()
 {
 
     if (!initalised)
-        return;
+        return false;
+
     //
     // Start request to stream servers
     //
@@ -272,20 +211,28 @@
     if (socket) {
         delete socket;
         socket = NULL;
-        }
-        
+    }
+
 
     if(log_level < 3) fprintf(stderr,"... Connecting to plotly's streaming servers...\n");
 
 
-    if (!dry_run && !socket) {
+    if (!dry_run) {
+        int pause = 1;
         socket = new TCPSocketConnection();
         while (socket->connect(dataURL, 80) < 0) {
-            fprintf(stderr,"... Couldn\'t connect to servers... trying again!\n");
-            wait(10);
+            if (pause > 30) {
+                fprintf(stderr,"Failed to connect. :-(\n");
+                delete socket;
+                return false;
+            }
+            fprintf(stderr,"... Couldn\'t connect to plotly's REST servers... trying again!\n");
+            wait(pause);
+            pause *= 2;
         }
     }
 
+
     if(log_level < 3) fprintf(stderr,"... Connected to plotly's streaming servers\n... Initializing stream\n");
 
     print_("POST / HTTP/1.1\r\n");
@@ -294,28 +241,29 @@
     print_("Transfer-Encoding: chunked\r\n");
     print_("Connection: close\r\n");
     print_("plotly-streamtoken: ");
-    print_(stream_tokens_[0]);
-    print_("\r\n");
-//    if(convertTimestamp) {
-//        print_("plotly-convertTimestamp: \"");
-//        print_(timezone);
-//        print_("\"");
-//        print_("\r\n");
-//    }
-    print_("\r\n");
+    print_(stream_token_);
+    printNetTerminator_();
+    if(convertTimestamp) {
+        print_("plotly-convertTimestamp: \"");
+        print_(timezone);
+        print_("\"");
+        printNetTerminator_();
+    }
+    printNetTerminator_();
 
     if(log_level < 3) fprintf(stderr,"... Done initializing, ready to stream!\n");
+    return true;
 }
 
 void plotly::closeStream()
 {
     if (socket) {
         if (socket->is_connected()) {
-          print_("0\r\n\r\n");
-          socket->close();
+            print_("0\r\n\r\n");
+            socket->close();
         }
         delete socket;
-    socket=NULL;
+        socket=NULL;
     }
 }
 
@@ -328,116 +276,65 @@
     }
 }
 
-void plotly::jsonStart(int i)
+void plotly::plot(unsigned long x, int y)
 {
-    // Print the length of the message in hex:
-    // 15 char for the json that wraps the data: {"x": , "y": }\n
-    // + 23 char for the token: , "token": "abcdefghij"
-    // = 38
-    printHex_(i+38);
-    print_("\r\n{\"x\": ");
-}
-void plotly::jsonMiddle()
-{
-    print_(", \"y\": ");
-}
-void plotly::jsonEnd(char *token)
-{
-    print_(", \"streamtoken\": \"");
-    print_(token);
-    print_("\"");
-    print_("}\n\r\n");
+    if (!initalised)
+        return;
+
+    reconnectStream();
+
+    // need to prefix with the length so print it once to get the content lenght and then a second time with the prefix.
+    int len = snprintf(buffer,k_bufferSize,"{\"x\": %lu, \"y\": %d}\n", x,y);
+    len = snprintf(buffer,k_bufferSize,"%x\r\n{\"x\": %lu, \"y\": %d}\n\r\n",len, x,y);
+    sendFormatedText(buffer,len);
 }
 
-int plotly::len_(int i)
-{
-    // int range: -32,768 to 32,767
-    if(i > 9999) return 5;
-    else if(i > 999) return 4;
-    else if(i > 99) return 3;
-    else if(i > 9) return 2;
-    else if(i > -1) return 1;
-    else if(i > -10) return 2;
-    else if(i > -100) return 3;
-    else if(i > -1000) return 4;
-    else if(i > -10000) return 5;
-    else return 6;
-}
-int plotly::len_(unsigned long i)
-{
-    // max length of unsigned long: 4294967295
-    if(i > 999999999) return 10;
-    else if(i > 99999999) return 9;
-    else if(i > 9999999) return 8;
-    else if(i > 999999) return 7;
-    else if(i > 99999) return 6;
-    else if(i > 9999) return 5;
-    else if(i > 999) return 4;
-    else if(i > 99) return 3;
-    else if(i > 9) return 2;
-    else return 1;
-}
-int plotly::len_(char *i)
-{
-    return strlen(i);
-}
-void plotly::plot(unsigned long x, int y, char *token)
+void plotly::plot(unsigned long x, float y)
 {
     if (!initalised)
         return;
 
     reconnectStream();
 
-//    int len = snprintf(buffer,k_bufferSize,"{\"x\": %lu, \"y\": %d, \"streamtoken\": \"%s\"}\n", x,y,token);
-//    len = snprintf(buffer,k_bufferSize,"%X\r\n{\"x\": %lu, \"y\": %d, \"streamtoken\": \"%s\"}\n\r\n",len, x,y,token);
-    int len = snprintf(buffer,k_bufferSize,"{\"x\": %lu, \"y\": %d}\n", x,y);
-    len = snprintf(buffer,k_bufferSize,"%x\r\n{\"x\": %lu, \"y\": %d}\n\r\n",len, x,y);
-    sendFormatedText(buffer,len);
-}
-
-void plotly::plot(unsigned long x, float y, char *token)
-{
-    if (!initalised)
-        return;
-
-    reconnectStream();
-
+    // need to prefix with the length so print it once to get the content lenght and then a second time with the prefix.
     int len = snprintf(buffer,k_bufferSize,"{\"x\": %lu, \"y\": %.3f}\n", x,y);
     len = snprintf(buffer,k_bufferSize,"%x\r\n{\"x\": %lu, \"y\": %.3f}\n\r\n",len, x,y);
-//    int len = snprintf(buffer,k_bufferSize,"{\"x\": %lu, \"y\": %.3f, \"streamtoken\": \"%s\"}\n", x,y,token);
-//    len = snprintf(buffer,k_bufferSize,"%X\r\n{\"x\": %lu, \"y\": %.3f, \"streamtoken\": \"%s\"}\n\r\n",len, x,y,token);
     sendFormatedText(buffer,len);
 }
 
 bool plotly::print_(int d)
 {
-    int32_t len = snprintf(buffer,k_bufferSize,"%d",d);
-    return sendFormatedText(buffer,len);
+    char smallBuffer[10];
+    int32_t len = snprintf(smallBuffer,10,"%d",d);
+    return sendFormatedText(smallBuffer,len);
 }
 
 bool plotly::print_(unsigned long d)
 {
-    int32_t len = snprintf(buffer,k_bufferSize,"%lu",d);
-    return sendFormatedText(buffer,len);
+    char smallBuffer[12];
+    int32_t len = snprintf(smallBuffer,12,"%lu",d);
+    return sendFormatedText(smallBuffer,len);
 }
 
 bool plotly::print_(float d)
 {
-    int32_t len = snprintf(buffer,k_bufferSize,"%f",d);
-    return sendFormatedText(buffer,len);
+    char smallBuffer[12];
+    int32_t len = snprintf(smallBuffer,12,"%f",d);
+    return sendFormatedText(smallBuffer,len);
 }
 
-bool plotly::print_(char *d)
+bool plotly::printNetTerminator_()
+{
+    return sendFormatedText("\r\n",2);
+}
+
+
+bool plotly::print_(char *d) // strings could be long, use the big buffer
 {
     int32_t len = snprintf(buffer,k_bufferSize,"%s",d);
     return sendFormatedText(buffer,len);
 }
 
-bool plotly::printHex_(uint16_t d)
-{
-    int32_t len = snprintf(buffer,k_bufferSize,"%X",d);
-    return sendFormatedText(buffer,len);
-}
 
 bool plotly::sendFormatedText(char* data, int size)
 {
@@ -448,46 +345,20 @@
         if (!socket) {
             fprintf(stderr,"\nTX failed, No network socket exists\n");
             return false;
-            }
+        }
         if (!(socket->is_connected())) {
             fprintf(stderr,"\nTX failed, Network socket not connected\n");
-            return false;           
-            }
-        
+            return false;
+        }
+
         int32_t sent = socket->send_all(data,size);
         if (sent == size)
             return true;
         else {
             fprintf(stderr,"\nTX failed to send _%s_ Sent %d of %d bytes\n",data,sent,size);
-            echoRxData();
             return false;
         }
     } else
         return true;
 }
 
-void plotly::echoRxData()
-{
-
-    int32_t dataIn = socket->receive(buffer,k_bufferSize -1);
-    if (dataIn < 0) {
-        if (socket->is_connected()) {
-            fprintf(stderr,"error reading network socket. Closing it\n");
-            socket->close();
-            delete socket;
-            socket = NULL;
-            }
-        else {
-            fprintf(stderr,"error reading network socket, socket isn't connected\n");
-            delete socket;
-            socket = NULL;
-            }
-    }
-    if(dataIn > 0) {
-        buffer[dataIn]=0;
-        fprintf(stderr,"Rx Data __");
-        fprintf(stderr,buffer);
-        fprintf(stderr,"__\n");
-    }
-    
-}
\ No newline at end of file