For this project I'm using an Arduino Uno with a ESP8266. I'm reading an ADC pin/pin's voltage on the Uno and wirelessly sending the data to plotly's server for real-time visualization. Plotly is a free online browser based tool for visualizing data, which also has a streaming feature for displaying your data in real-time. Plotly is great because any device that has a browser and is connected to the internet (smartphone, PC, tablet, etc) can see the real-time data. This is not a full professional solution I'm offering here, just a quick demonstration on how this can be done with these common cheap parts.

*I highly recommend you check out my other project, where I run similar code natively (no Arduino needed) on the ESP. It is much less work then this project.

I was helping out someone who wanted to send real-time data wirelessly to a smartphone/PC on a tight budget. I found this method of displaying real-time data to be useful. Even though we did not end up using this solution, I can see someone using this for a home weather station or something similar.

The Arduino Sketch

Here is my Arduino sketch. It is made for Arduino Uno/Pro Mini paired with a ESP8266 running the 0018000902-AI03 firmware (I have inlcuded the firmware bin file in the instructions section). Originally my code was development on an Arduino Due which has 96 KB of SRAM. This is plenty of SRAM to store the strings used in the original sketch, but because the Uno has only 2 KB of SRAM it's much wiser to store this in flash. This sketch compiles with 30% flash and 25% SRAM used!! Leaves plenty of room for more development. The code makes use of hardware UART (digital pins 0 & 1) to communicate to the ESP8266 and soft UART (digital pin 11) for debugging purposes.

#define ssid       "YourSSID"
#define pass       "YourWiFiPassword"
#define userName   "YourPlotlyUserName"
#define APIKey     "xxxxxxxxxx"
#define fileName   "test"
#define fileopt    "overwrite"
#define nTraces    2
#define maxpoints  "30"
#define world_readable true
#define convertTimestamp true
#define timezone "Australia/Melbourne"
#include <SoftwareSerial.h>
#include <avr/pgmspace.h>
#define prog_char  char PROGMEM
char *tokens[nTraces] = {"AAAAAAAAAA","BBBBBBBBBB"};
char stream_site[25] = {0};
SoftwareSerial mySerial(10, 11); // RX, TX
const PROGMEM  char  cmd_0[] = {"AT\r\n"};
const PROGMEM  char  cmd_1[] = {"ATE1\r\n"};
const PROGMEM  char  cmd_2[] = {"AT+CWMODE=1\r\n"};
const PROGMEM  char  cmd_3[] = {"AT+CIPMODE=0\r\n"};
const PROGMEM  char  cmd_4[] = {"AT+RST\r\n"};
const PROGMEM  char  cmd_5[] = {"AT+CIPMUX=1\r\n"};
const PROGMEM  char  cmd_6[] = {"AT+CWJAP=\""};
const PROGMEM  char  cmd_7[] = {"AT+CIPCLOSE=\""};
const PROGMEM  char  cmd_8[] = {"AT+CIPSTART=0,\"TCP\",\""};
const PROGMEM  char  cmd_9[] = {"AT+CIPSEND=0,"};
const PROGMEM  char  resp_0[] = {"OK"};
const PROGMEM  char  resp_1[] = {"ready"};
const PROGMEM  char  resp_2[] = {"no change"};
const PROGMEM  char  resp_3[] = {"CONNECT"};
const PROGMEM  char  resp_4[] = {"Unlink"};
const PROGMEM  char  resp_5[] = {"Linked"};
const PROGMEM  char  resp_6[] = {">"};
const PROGMEM  char  resp_7[] = {"~"};
const PROGMEM  char  error[] = {"*ERROR "};
const PROGMEM  char  error_0[] = {"0*"};
const PROGMEM  char  error_1[] = {"1*"};
const PROGMEM  char  error_2[] = {"2*"};
const PROGMEM  char  error_3[] = {"3*"};
const PROGMEM  char  error_4[] = {"4*"};
const PROGMEM  char  error_5[] = {"5*"};
const PROGMEM  char  error_6[] = {"6*"};
const PROGMEM  char  error_7[] = {"7*"};
const PROGMEM  char  error_8[] = {"8*"};
const PROGMEM  char  error_9[] = {"9*"};
const PROGMEM  char  error_10[] = {"10*"};
const PROGMEM  char  error_11[] = {"11*"};
const PROGMEM  char  error_12[] = {"12*"};
const PROGMEM  char  error_13[] = {"13*"};
const PROGMEM  char  error_14[] = {"14*"};
const PROGMEM  char  error_15[] = {"15*"};
const PROGMEM  char  error_16[] = {"16*"};
const PROGMEM  char  string_0[] = {"Initializing plot with Plot.ly server...\r\n"};
const PROGMEM  char  string_1[] = {"\",\""};
const PROGMEM  char  string_2[] = {"\""};
const PROGMEM  char  string_3[] = {"\",80"};
const PROGMEM  char  string_4[] = {"POST /clientresp HTTP/1.1\r\n"};
const PROGMEM  char  string_5[] = {"Host: plot.ly:80\r\n"};
const PROGMEM  char  string_6[] = {"User-Agent: Arduino/0.6.0\r\n"};
const PROGMEM  char  string_7[] = {"Content-Type: application/x-www-form-urlencoded\r\n"};
const PROGMEM  char  string_8[] = {"Content-Length: "};
const PROGMEM  char  string_9[] = {"version=2.3&origin=plot&platform=arduino&un="};
const PROGMEM  char  string_10[] = {"&key="};
const PROGMEM  char  string_11[] = {"&args=["};
const PROGMEM  char  string_12[] = {"{\"y\": [], \"x\": [], \"type\": \"scatter\", \"stream\": {\"token\": \""};
const PROGMEM  char  string_13[] = {"\", \"maxpoints\": "};
const PROGMEM  char  string_14[] = {"}}"};
const PROGMEM  char  string_15[] = {", "};
const PROGMEM  char  string_16[] = {"]&kwargs={\"fileopt\": \""};
const PROGMEM  char  string_17[] = {"\", \"filename\": \""};
const PROGMEM  char  string_18[] = {"\", \"world_readable\": "};
const PROGMEM  char  string_19[] = {"true"};
const PROGMEM  char  string_20[] = {"false"};
const PROGMEM  char  string_21[] = {"}"};
const PROGMEM  char  string_22[] = {"Successfully Initialized.\r\n"};
const PROGMEM  char  string_23[] = {"Please visit: \"http://plot.ly/~"};
const PROGMEM  char  string_24[] = {"\"."};
const PROGMEM  char  string_25[] = {"POST / HTTP/1.1\r\n"};
const PROGMEM  char  string_26[] = {"Host: arduino.plot.ly\r\n"};
const PROGMEM  char  string_27[] = {"User-Agent: Arduino\r\n"};
const PROGMEM  char  string_28[] = {"Transfer-Encoding: chunked\r\n"};
const PROGMEM  char  string_29[] = {"Connection: close\r\n"};
const PROGMEM  char  string_30[] = {"plotly-convertTimestamp: \""};
const PROGMEM  char  string_31[] = {"\"\r\n\r\n"};
const PROGMEM  char  string_32[] = {"\r\n{\"x\": "};
const PROGMEM  char  string_33[] = {", \"y\": "};
const PROGMEM  char  string_34[] = {", \"streamtoken\": \""};
const PROGMEM  char  string_35[] = {"\"}\n\r\n0\r\n\r\n"};
const char* const resp_table[] PROGMEM = {resp_0, resp_1, resp_2, resp_3, resp_4, resp_5, resp_6, resp_7};
char buffer[20]={0};
/* -------------- Setup ------------------ */
void setup() {
  // Setup Serial
  mySerial.begin(9600);
  Serial.begin(9600);
  Serial.setTimeout(8000);
  delay(1000);
  ESP8266_Init();
  plotly_init();
  ESP8266_Disconnect(0);   // Making sure disconnected
  ESP8266_Connect("arduino.plot.ly");
}
/* ------------- Loop -------------------- */
void loop() {
  mySerial.println("Reading ADC...");
  int val = analogRead(0);
  int val2 = analogRead(1);
  mySerial.println("Sending Jason...");
  long time_ms = millis();
  while(!plotly_plot(time_ms,val,tokens[0])){ESP8266_Connect("arduino.plot.ly");}
  while(!plotly_plot(time_ms,val2,tokens[1])){ESP8266_Connect("arduino.plot.ly");}
}
/* --------------- Functions -------------------- */
void mySerial_PrintConstString(const prog_char str[]) {
  char c;
  if(!str) return;
  while((c = pgm_read_byte(str++)))
    mySerial.write(c);
}
void Serial_PrintConstString(const prog_char str[]) {
  char c;
  if(!str) return;
  while((c = pgm_read_byte(str++)))
    Serial.write(c);
}
boolean find_resp(unsigned char a, const prog_char error_str[]){
  strcpy_P(buffer, (char*)pgm_read_word(&(resp_table[a])));
  if(!Serial.find(buffer)){
    mySerial_PrintConstString(error);
    mySerial_PrintConstString(error_str);
    mySerial.println();
    return false;
  }
  else{
    return true;
  }
}
void ESP8266_Init(){
  mySerial_PrintConstString(string_0);                   // send debug "Initializing plot with Plot.ly server...\r\n"
  // Startup test
  Serial_PrintConstString(cmd_0);                        // send "AT\r\n"
  if(!find_resp(0,error_0)){while(1){}}                  // find "OK"
  // Turn ECHO off
  Serial_PrintConstString(cmd_1);                        // send "ATE1\r\n"
  if(!find_resp(0,error_1)){while(1){}}                  // find "OK"
  // Put WiFi into Station mode
  Serial_PrintConstString(cmd_2);                        // send "AT+CWMODE=1\r\n"
  if(!find_resp(2,error_2)){                             // find "no change"
    Serial_PrintConstString(cmd_2);                      // send "AT+CWMODE=1\r\n"
    if(!find_resp(0,error_3)){while(1){}}                // find "OK"
  }
  // Set data transmission mode to no data (0)
  Serial_PrintConstString(cmd_3);                        // send "AT+CIPMODE=0\r\n"
  if(!find_resp(0,error_4)){while(1){}}                  // find "OK"
  // Restart ESP8266
  Serial_PrintConstString(cmd_4);                        // send "AT+RST\r\n"
  if(!find_resp(1,error_5)){while(1){}}                  // find "ready"
  // Enable multiple connections (MUX)
  Serial_PrintConstString(cmd_5);                        // send "AT+CIPMUX=1\r\n"
  if(!find_resp(0,error_6)){while(1){}}                  // find "OK"
  Serial_PrintConstString(cmd_6);                        // send "AT+CWJAP=\"
  Serial.print(ssid);                                    // send ssid
  Serial_PrintConstString(string_1);                     // send "\",\""
  Serial.print(pass);                                    // send password
  Serial_PrintConstString(string_2);                     // send "\""
  Serial.println();
  if(!find_resp(0,error_7)){while(1){}}                  // find "OK"
}
void ESP8266_Disconnect(unsigned char id){
  Serial_PrintConstString(cmd_7);                        // send "AT+CIPCLOSE=\""
  Serial.print(id);                                      // send id
  Serial_PrintConstString(string_2);                     // send "\""
  Serial.println();
  if(!find_resp(4,error_8)){                             // find "Unlink"
    Serial_PrintConstString(cmd_7);                      // send "AT+CIPCLOSE=\""
    Serial.print(id);                                    // send id
    Serial_PrintConstString(string_2);                   // send "\""
    Serial.println();
    while(1){}
  }
}
void ESP8266_Connect(char *url){
  int p = (int)url;
  Serial_PrintConstString(cmd_8);                // send "AT+CIPSTART=0,\"TCP\",\""
  url = (char *)p;
  while(*url){                                   // send URL
    Serial.print(*url);
    url++;
  }
  Serial_PrintConstString(string_3);                       // send "\",80"
  Serial.println();
  if(!find_resp(5,error_9)){                               // find "Linked"
    Serial_PrintConstString(cmd_8);                        // send "AT+CIPSTART=0,\"TCP\",\""
    url = (char *)p;
    while(*url){                                           // send URL
      Serial.print(*url);
      url++;
    }
    Serial_PrintConstString(string_3);                      // send "\",80"
    Serial.println();
    if(find_resp(3,error_10)){                              // find "CONNECT"
      ESP8266_Disconnect(0);
      Serial_PrintConstString(cmd_8);                       // send "AT+CIPSTART=0,\"TCP\",\""
      url = (char *)p;
      while(*url){                                          // send URL
        Serial.print(*url);
        url++;
      }
      Serial_PrintConstString(string_3);                    // send "\",80"
      Serial.println();
      if(!find_resp(5,error_11)){while(1){}}                // find "Linked"
    }
  }
}
void plotly_init(){
  unsigned int i = 0;
  char charbuffer;
  unsigned int contentLength = 126 + strlen(userName) + strlen(fileopt) + nTraces*(87+strlen(maxpoints)) + (nTraces - 1)*2 + strlen(fileName);
  if(world_readable){
    contentLength += 4;
  }
  else{
    contentLength += 5;
  }
  String contentLengthString = String(contentLength);
  const char* contentLengthConstString = contentLengthString.c_str();
  unsigned int postLength = contentLength + 141 + strlen(contentLengthConstString);
  ESP8266_Connect("plot.ly");
  Serial_PrintConstString(cmd_9);                  // send "AT+CIPSEND=0,"
  Serial.println(postLength);
  if(find_resp(6,error_12)){                       // find ">"
    Serial_PrintConstString(string_4);             // send "POST /clientresp HTTP/1.1\r\n"
    Serial_PrintConstString(string_5);             // send "Host: plot.ly:80\r\n"
    Serial_PrintConstString(string_6);             // send "User-Agent: Arduino/0.6.0\r\n"
     Serial_PrintConstString(string_7);            // send "Content-Type: application/x-www-form-urlencoded\r\n"
    Serial_PrintConstString(string_8);             // send "Content-Length: "
    Serial.print(contentLength);
    Serial.println();
    Serial.println();      
    Serial_PrintConstString(string_9);             // send "version=2.3&origin=plot&platform=arduino&un="
    Serial.print(userName);                        // send userName
    Serial_PrintConstString(string_10);             // send "&key="
    Serial.print(APIKey);                          // send APIKey
    Serial_PrintConstString(string_11);            // send "&args=["
    for(int i=0; i<nTraces; i++){
        Serial_PrintConstString(string_12);        // send "{\"y\": [], \"x\": [], \"type\": \"scatter\", \"stream\": {\"token\": \""
        Serial.print(tokens[i]);                   // send token
        Serial_PrintConstString(string_13);        // send "\", \"maxpoints\": "
        Serial.print(maxpoints);                   // send maxpoints
        Serial_PrintConstString(string_14);        // send "}}"
        if(nTraces > 1 && i != nTraces-1){
           Serial_PrintConstString(string_15);     // send ", "
        }
    }
    Serial_PrintConstString(string_16);            // send "]&kwargs={\"fileopt\": \""
    Serial.print(fileopt);                         // send fileopt
    Serial_PrintConstString(string_17);            // send "\", \"filename\": \""
    Serial.print(fileName);                        // send fileName
    Serial_PrintConstString(string_18);            // send "\", \"world_readable\": "
    if(world_readable){
      Serial_PrintConstString(string_19);          // send "true"
    }
    else{
      Serial_PrintConstString(string_20);          // send "false"
    }
    Serial_PrintConstString(string_21);            // send "}"
    if(find_resp(7,error_13)){                     // find "~"
      i=0;
      while(1){
        while(!Serial.available()){}
        charbuffer = Serial.read();
        if(charbuffer == 34){break;}
        stream_site[i] = charbuffer;
        i++;
      }
      if(!find_resp(0,error_14)){             // find "OK"
        while(1){}
      }
      mySerial_PrintConstString(string_22);   // send debug "Successfully Initialized.\r\n"
      mySerial_PrintConstString(string_23);   // send debug "Please visit: \"http://plot.ly/~"
      i=0;
      while(stream_site[i]){
        mySerial.print(stream_site[i]);
        i++;
      }
      mySerial_PrintConstString(string_24);    // send debug "\"."
      mySerial.println();
    }
    else{
      while(1){}
    }
  }
  else{
    while(1){}
  }
}
bool plotly_plot(unsigned long x, int y, char *token){
  String xString = String(x);
  String yString = String(y);
  const char* xConstString = xString.c_str();
  const char* yConstString = yString.c_str();
  unsigned int jasonLength = 44 + strlen(xConstString) +  strlen(yConstString);
  String jasonLengthString = String(jasonLength, HEX);
  const char* ConstJasonLengthString = jasonLengthString.c_str();
  unsigned int postLength = 167 + strlen(ConstJasonLengthString) + jasonLength;
  Serial_PrintConstString(cmd_9);           // send "AT+CIPSEND=0,"
  Serial.println(postLength);
  if(find_resp(6,error_15)){                // find ">"
    Serial_PrintConstString(string_25);     // send "POST / HTTP/1.1\r\n"
    Serial_PrintConstString(string_26);     // send "Host: arduino.plot.ly\r\n"
    Serial_PrintConstString(string_27);     // send "User-Agent: Arduino\r\n"
    Serial_PrintConstString(string_28);     // send "Transfer-Encoding: chunked\r\n"
    Serial_PrintConstString(string_29);     // send "Connection: close\r\n"
    Serial_PrintConstString(string_30);     // send "plotly-convertTimestamp: \"Australia/Melbourne\"\r\n\r\n"
    Serial.print(timezone);
    Serial_PrintConstString(string_31);
    
  }
  else{
    return false;
  }
  Serial.print(jasonLengthString);
  Serial_PrintConstString(string_32);       // send "\r\n{\"x\": "
  Serial.print(x);                          // send x
  Serial_PrintConstString(string_33);       // send ", \"y\": "
  Serial.print(y);                          // send y
  Serial_PrintConstString(string_34);       // send ", \"streamtoken\": \""
  while(*token){                            // send token
    Serial.print(*token);
    token++;
  }
  Serial_PrintConstString(string_35);       // send "\"}\n\r\n0\r\n\r\n"
  if(find_resp(0,error_16)){                // find "OK"
    mySerial.println("Sent data!");
    return true;
  }
  else{
    mySerial.println("*Couldn't send data!!*");
    return false;
  }  
}

Now you have created a real-time data logger/grapher using Plotly :).