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.

Files at this revision

API Documentation at this revision

Comitter:
AndyA
Date:
Tue Jul 29 13:43:31 2014 +0000
Parent:
7:9409a72ab6c0
Commit message:
Documentation tidy up and fix a stupid error in the merge between the documented and the multi-line branches.

Changed in this revision

plotly.cpp Show annotated file Show diff for this revision Revisions of this file
plotly.cpp.orig Show diff for this revision Revisions of this file
plotly.h Show annotated file Show diff for this revision Revisions of this file
plotly.h.orig Show diff for this revision Revisions of this file
diff -r 9409a72ab6c0 -r d4f705ba2ea5 plotly.cpp
--- a/plotly.cpp	Tue Jul 29 13:30:31 2014 +0000
+++ b/plotly.cpp	Tue Jul 29 13:43:31 2014 +0000
@@ -4,13 +4,13 @@
 #define plotlyURL "plot.ly"
 #define dataURL "arduino.plot.ly"
 
-plotly::plotly(const char *username, const char *api_key, const char** stream_tokens, const char *filename, int nTraces)
+plotly::plotly(const char *username, const char *api_key, const char* stream_tokens[], const char *filename, int nTraces)
 {
     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_tokens_ = stream_tokens;
     filename_ = filename;
     maxpoints = 30;
     world_readable = true;
@@ -39,14 +39,6 @@
 
 bool plotly::init()
 {
-
-    fprintf(stderr,"%d tokens\n",nTraces_);
-    wait(1);
-    for (int i = 0; i<nTraces_; i++) {
-        fprintf(stderr,"%s\n",*(stream_tokens_+i));
-        wait(1);
-    }
-
     //
     //  Create plot with a REST post to plotly
     //  See the clientresp section of https://plot.ly/rest/ for details
diff -r 9409a72ab6c0 -r d4f705ba2ea5 plotly.cpp.orig
--- a/plotly.cpp.orig	Tue Jul 29 13:30:31 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,378 +0,0 @@
-#include "plotly.h"
-#include "mbed.h"
-
-#define plotlyURL "plot.ly"
-#define dataURL "arduino.plot.ly"
-
-plotly::plotly(char *username, char *api_key, char* stream_token, char *filename)
-{
-    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_token_ = stream_token;
-    filename_ = filename;
-    maxpoints = 30;
-    world_readable = true;
-    convertTimestamp = false;
-    timezone = "America/Montreal";
-    fileopt = "overwrite";
-
-    socket = NULL;
-
-    initalised = false;
-}
-
-
-plotly::~plotly()
-{
-    closeStream();
-
-}
-
-
-bool plotly::init()
-{
-
-    //
-    //  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");
-    } else if(log_level < 3) {
-        fprintf(stderr,"... Attempting to connect to plotly's REST servers\n");
-    }
-
-    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(pause);
-            pause *= 2;
-        }
-    }
-
-    if(log_level < 3) fprintf(stderr,"... Connected to plotly's REST servers\n");
-
-    if(log_level < 3) fprintf(stderr,"... Sending HTTP Post to plotly\n");
-
-    print_("POST /clientresp HTTP/1.1\r\n");
-    print_("Host: 107.21.214.199\r\n");
-    print_("User-Agent: Arduino/0.5.1\r\n");
-    print_("plotly-streamtoken: ");
-    print_(stream_token_);
-    printNetTerminator_();
-
-    print_("Content-Length: ");
-
-    // 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_);
-    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");
-
-    print_(lineLen);
-
-    printNetTerminator_();
-    printNetTerminator_();
-
-    sendFormatedText(buffer,lineLen);
-
-    printNetTerminator_();
-
-    //
-    // Wait for a response
-    // Parse the response for the "All Streams Go!" and proceed to streaming
-    // if we find it
-    //
-
-    char allStreamsGo[] = "All Streams Go!";
-    int asgCnt = 0; // asg stands for All Streams Go
-    char url[] = "\"url\": \"http://107.21.214.199/~";
-    char fid[4];
-    int fidCnt = 0;
-    int urlCnt = 0;
-    int usernameCnt = 0;
-    bool proceed = false;
-    bool fidMatched = false;
-    char c;
-
-    if(log_level < 2) {
-        fprintf(stderr,"... Sent message, waiting for plotly's response...\n");
-    }
-
-    if(!dry_run) {
-        while(!proceed) {
-            int32_t dataIn = socket->receive(buffer,k_bufferSize -1);
-            if (dataIn < 0) {
-                if(log_level < 3) fprintf(stderr,"error reading network socket\n");
-                break;
-            }
-            if(dataIn > 0) {
-                buffer[dataIn]=0;
-
-                if(log_level < 2) fprintf(stderr,buffer);
-
-                for (int i = 0; i<dataIn; i++) {
-                    c = buffer[i];
-                    //
-                    // Attempt to read the "All streams go" msg if it exists
-                    // by comparing characters as they roll in
-                    //
-
-                    if(asgCnt == strlen(allStreamsGo) && !proceed) {
-                        proceed = true;
-                    } else if(allStreamsGo[asgCnt]==c) {
-                        asgCnt += 1;
-                    } else if(asgCnt > 0) {
-                        // reset counter
-                        asgCnt = 0;
-                    }
-
-                    //
-                    // Extract the last bit of the URL from the response
-                    // The url is in the form http://107.21.214.199/~USERNAME/FID
-                    // We'll character-count up through char url[] and through username_, then start
-                    // filling in characters into fid
-                    //
-
-                    if(log_level < 3) {
-                        if(url[urlCnt]==c && urlCnt < strlen(url)) {
-                            urlCnt += 1;
-                        } else if(urlCnt > 0 && urlCnt < strlen(url)) {
-                            // Reset counter
-                            urlCnt = 0;
-                        }
-                        if(urlCnt == strlen(url) && fidCnt < 4 && !fidMatched) {
-                            // We've counted through the url, start counting through the username
-                            if(usernameCnt < strlen(username_)+2) {
-                                usernameCnt += 1;
-                            } else {
-                                // the url ends with "
-                                if(c != '"') {
-                                    fid[fidCnt] = c;
-                                    fidCnt += 1;
-                                } else if(fidCnt>0) {
-                                    fidMatched = true;
-                                }
-
-                            }
-                        }
-                    }
-                }
-            }
-            wait(0.1);
-        }
-    }
-
-    if(!dry_run && !proceed && log_level < 4) {
-        fprintf(stderr,"... Error initializing stream, aborting. Try again or get in touch with Chris at chris@plot.ly\n");
-    }
-
-    if(!dry_run && proceed && log_level < 3) {
-        fprintf(stderr,"... A-ok from plotly, All Streams Go!\n");
-        if(fidMatched) {
-            fprintf(stderr,"... View your streaming plot here: https://plot.ly/~");
-            fprintf(stderr,username_);
-            fprintf(stderr,"/");
-            for(int i=0; i<fidCnt; i++) {
-                fprintf(stderr,"%c",fid[i]);
-            }
-            fprintf(stderr,"\n");
-        }
-    }
-
-    if (proceed || dry_run) {
-        initalised = true;
-    }
-    if (socket) {
-        delete socket;
-        socket=NULL;
-    }
-    return initalised;
-}
-
-bool plotly::openStream()
-{
-
-    if (!initalised)
-        return false;
-
-    //
-    // Start request to stream servers
-    //
-
-    if (socket) {
-        delete socket;
-        socket = NULL;
-    }
-
-
-    if(log_level < 3) fprintf(stderr,"... Connecting to plotly's streaming servers...\n");
-
-
-    if (!dry_run) {
-        int pause = 1;
-        socket = new TCPSocketConnection();
-        while (socket->connect(dataURL, 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(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");
-    print_("Host: arduino.plot.ly\r\n");
-    print_("User-Agent: Python\r\n");
-    print_("Transfer-Encoding: chunked\r\n");
-    print_("Connection: close\r\n");
-    print_("plotly-streamtoken: ");
-    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();
-        }
-        delete socket;
-        socket=NULL;
-    }
-}
-
-void plotly::reconnectStream()
-{
-    while(!dry_run && (!socket || !socket->is_connected())) {
-        if(log_level<4) fprintf(stderr,"... Disconnected from streaming servers\n");
-        closeStream();
-        openStream();
-    }
-}
-
-void plotly::plot(unsigned long x, int y)
-{
-    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);
-}
-
-void plotly::plot(unsigned long x, float y)
-{
-    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);
-    sendFormatedText(buffer,len);
-}
-
-void plotly::plot(float x, float y)
-{
-    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\": %.3f, \"y\": %.3f}\n", x,y);
-    len = snprintf(buffer,k_bufferSize,"%x\r\n{\"x\": %.3f, \"y\": %.3f}\n\r\n",len, x,y);
-    sendFormatedText(buffer,len);
-}
-
-
-bool plotly::print_(int d)
-{
-    char smallBuffer[10];
-    int32_t len = snprintf(smallBuffer,10,"%d",d);
-    return sendFormatedText(smallBuffer,len);
-}
-
-bool plotly::print_(unsigned long d)
-{
-    char smallBuffer[12];
-    int32_t len = snprintf(smallBuffer,12,"%lu",d);
-    return sendFormatedText(smallBuffer,len);
-}
-
-bool plotly::print_(float d)
-{
-    char smallBuffer[12];
-    int32_t len = snprintf(smallBuffer,12,"%f",d);
-    return sendFormatedText(smallBuffer,len);
-}
-
-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::sendFormatedText(char* data, int size)
-{
-    if(log_level < 2) {
-        fprintf(stderr,"%s",data);
-    }
-    if(!dry_run) {
-        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;
-        }
-
-        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);
-            return false;
-        }
-    } else
-        return true;
-}
-
diff -r 9409a72ab6c0 -r d4f705ba2ea5 plotly.h
--- a/plotly.h	Tue Jul 29 13:30:31 2014 +0000
+++ b/plotly.h	Tue Jul 29 13:43:31 2014 +0000
@@ -10,16 +10,20 @@
 
 /** Create a plot on plot.ly
 *
-* Based on the Ardunio code supplied by plot.ly
+* Creates a streaming X/Y scatter plot with line on the plot.ly site.
+* Multiple lines can be drawn however each line currently requires a seperate network socket so you could easily run out of resources if you're not careful.
+* I've only tested 1 and 2 line plots.
 *
-* Creates a streaming X/Y scatter plot with line on the plot.ly site.
-* Update periods can be between 50ms and 60s due to limitations imposed by plot.ly.
+* In theory each line could be plotted by a different mbed but this would require some changes to the way charts are initalised.
+*
+* Update periods can be between 50ms and 60s. Anything faster will be filtered, anything slower will result in the connection getting closed.
 * 
 * Requires an mbed with network support.
 * 
-* Provided as is, it works for me but your mileage may vary. Sorry, I don't have time to offer much support on this.
+* Based on the Ardunio code supplied by plot.ly and provided as is, it works for me but your mileage may vary.
+* Sorry, I don't have time to offer much support on this.
 * 
-* You will need to create a plot.ly account and then go to https://plot.ly/settings to get your API key and a streaming token.
+* You will need to create a plot.ly account and then go to https://plot.ly/settings to get your API key and streaming tokens.
 * 
 * See Plotly_HelloWorld for a sample implimentation.
 * 
@@ -35,7 +39,7 @@
     @param filename The name of the file to save the chart as
     @param nTraces The number of traces (MUST match the size of stream_tokens, can be omitted for a single line)
     */
-        plotly(const char *username, const char *api_key, const char ** stream_tokens, const char *filename, int nTraces = 1);
+        plotly(const char *username, const char *api_key, const char *stream_tokens[], const char *filename, int nTraces = 1);
 
         ~plotly();
         
@@ -45,7 +49,7 @@
         
         Time taken for this function can vary depending on network delays.
         
-        If you wish to change any of the options line max points or world readability then make sure you change them BEFORE calling this function.       
+        If you wish to change any of the options like max points or world readability then make sure you change them BEFORE calling this function.       
         */
         bool init();
 
@@ -85,7 +89,7 @@
         */
         void openStreams();
         
-        /** close all the streaming connections
+        /** Close all the streaming connections
         
         Call to tidy up and free up system resources once there is no more data to send
         */
diff -r 9409a72ab6c0 -r d4f705ba2ea5 plotly.h.orig
--- a/plotly.h.orig	Tue Jul 29 13:30:31 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,152 +0,0 @@
-#ifndef plotly_streaming_ethernet_h
-#define plotly_streaming_ethernet_h
-
-#include <EthernetInterface.h>
-#include <TCPSocketConnection.h>
-
-// size of the large buffer used for constructing messages.
-#define k_bufferSize 400
-
-
-/** Create a plot on plot.ly
-*
-* Based on the Ardunio code supplied by plot.ly
-*
-* Creates a streaming X/Y scatter plot with line on the plot.ly site.
-* Update periods can be between 50ms and 60s due to limitations imposed by plot.ly.
-* 
-* Requires an mbed with network support.
-* 
-* Provided as is, it works for me but your mileage may vary. Sorry, I don't have time to offer much support on this.
-* 
-* You will need to create a plot.ly account and then go to https://plot.ly/settings to get your API key and a streaming token.
-* 
-* See Plotly_HelloWorld for a sample implimentation.
-* 
-*/
-
-class plotly
-{
-    public:
-    /**
-    @param username Your plot.ly username
-    @param api_key Your plot.ly API key
-    @param stream_token A plot.ly streaming token for your plot.ly account
-    @param filename The name of the file to save the chart as
-    */
-        plotly(char *username, char *api_key, char* stream_token, char *filename);
-        /**
-        */
-        ~plotly();
-        
-        /** Initalises the chart
-        
-        This fucntion creates a blank chart on the plot.ly system and configures it to recieve streamed data using the specified token
-        
-        Time taken for this function can vary depending on network delays.
-        
-        If you wish to change any of the options line max points or world readability then make sure you change them BEFORE calling this function.       
-        */
-        bool init();
-
-        /**
-        Adds a point to the chart. The chart MUST be initalised before calling this.
-        Note, if the streaming network port is closed then this will attempt to open the port and re-establish the stream connection, this could block for a while.
-        
-        @param x The X value.
-        @param y The y value.
-        */
-        void plot(unsigned long x, int y);
-        /**
-        Adds a point to the chart. The chart MUST be initalised before calling this.
-        Note, if the streaming network port is closed then this will attempt to open the port and re-establish the stream connection, this could block for a while.
-        
-        @param x The X value.
-        @param y The y value.
-        */
-        void plot(unsigned long x, float y);
-
-        /**
-        Adds a point to the chart. The chart MUST be initalised before calling this.
-        Note, if the streaming network port is closed then this will attempt to open the port and re-establish the stream connection, this could block for a while.
-        
-        @param x The X value.
-        @param y The y value.
-        */
-        void plot(float x, float y);
-
-        /**
-        Opens the streaming connection.
-        
-        Normally you'd do this after a sucessful call to init() and before starting plotting in order to avoid a connection delays when you first call plot()
-        */
-        bool openStream();
-        /**
-        closes the streaming connection
-        */
-        void closeStream();
-
-        /**
-         output message level
-         Messages are sent to stderr (which defaults to the mBed USB programing/debug port).
-          0 = Debugging, 1 = Informational, 2 = Status, 3 = Errors (default), 4 = Quiet
-          */
-        int log_level;
-
-        /**
-        set true to not actually connect to the network..
-        */
-        bool dry_run;
-
-        /**
-        Maximum points to display on the streaming chart, once you go over this old points will no longer be displayed.
-        Defaults to 30
-        */
-        int maxpoints;
-        
-        /**
-        Sets whether the chart will be public or not.
-        Defaults to true
-        */
-        bool world_readable;
-        
-        /**
-        Converts timestamps to the local time zone
-        */
-        bool convertTimestamp;
-        /**
-        Timezone string to use
-        */
-        char *timezone;
-        /**
-        Sets what to do if the file already exists, valid options are:
-        "new","overwrite" (default),"append","extend"
-        */
-        char *fileopt;
-
-    private:
-
-        void reconnectStream();
-
-        bool print_(int d);
-        bool print_(unsigned long d);
-        bool print_(float d);
-        bool print_(char *d);
-        bool printNetTerminator_();
- 
-        
-        bool sendFormatedText(char* data, int size);
-
-        char buffer[512];
-//        char rxBuffer[128];
-        TCPSocketConnection *socket;
-        
-        char *username_;
-        char *api_key_;
-        char *stream_token_;
-        char *filename_;
-        
-        bool initalised;
-
-};
-#endif