Using Esp8266 to read data from ThingSpeak

Hi there. I'm trying to understand how I can read data from my ThingSpeak channel using the Esp8266 (esp-01) module with my Uno board. I've already managed to send the data. The problem is that every tutorial that I have found uses the NodeMcu module, which I don't possess. Is there a way to read such data? In order to send it I used the AT commands. I'm fine with using the ThingSpeak library if I have to. Thanks for helping me.

Post the code you have that sends data.

String AP = "MyWifiName";                                                  // WiFi NAME
String PASS = "MyWifiPassword";                                                  // WiFi PASSWORD
String API = "MyApikey";                                                    // Write API key (dal ThingSpeak channel)
String HOST = "api.thingspeak.com";
String PORT = "80";
int countTimeCommand; 
String message;

int X1=4;         // variabili di prova
int X2=5;
int X3=6;

void setup() {
  Serial.begin(115200);     // comunica via seriale (0, 1) : NOTA: durante il caricamento script stacca i pin 0 e 1 (ricollegali dopo)

  sendCommand("AT",5,"OK");
  sendCommand("AT+CWMODE=1",5,"OK");
  sendCommand("AT+CWJAP=\""+AP+"\",\""+PASS+"\"",20,"OK");  //connessione al router wifi
}

void loop() {
  
  message="GET /update?api_key="+API+"&field1="+X1+"&field2="+X2+"&field3="+X3;

  sendCommand("AT+CIPMUX=1",5,"OK");
  sendCommand("AT+CIPSTART=0,\"TCP\",\""+HOST+"\","+PORT,15,"OK");
  sendCommand("AT+CIPSTO=10",5,"OK");
  sendCommand("AT+CIPSEND=0,"+String(message.length()+4),4,">");
  Serial.println(message);
  sendCommand("AT+CIPCLOSE=0",5,"OK");
  
  delay(15000);           // ricorda che su ThingSpeak non devono passare meno di 15 s tra un invio e l'altro
     
}

void sendCommand(String command,int maxTime,char readReplay[])    // funzione di invio comando tra arduino e l'esp
{
  while(countTimeCommand<maxTime)
  {
    Serial.println(command);
    if(Serial.find(readReplay))
    {
      break;
    }
    countTimeCommand++;
  }
  countTimeCommand=0;
}

It looks like you can do it with another GET, see here.

Then you'll need to parse the JSON or XML it returns, which may be a bit tricky to debug as you're using serial to talk to the ESP. You may want to use SoftwareSerial for that so you can display what you get back from the service on the serial monitor.

Ok thanks, I'll try using the GET method, I have one question though. Where is the data stored when I get it from the cloud? Can I save it in a simple variable? As far as the parsing part I think I could use a little help. Thank you for answering my question

You will read the data from the serial port. Maybe into a buffer, perhaps character by character and parse as you read.

Just echo it to the monitor to start with though.

Ok I modified my code in order to read the data. I also used the SoftwareSerial library to have 2 different serial connections: the one with the esp and the one to my pc. I did this so I could see what is happening on my pc.

#include <SoftwareSerial.h>

SoftwareSerial esp8266(2,3);

String AP = "Telefono";                                                  // WiFi NAME
String PASS = "caccacca";                                                  // WiFi PASSWORD
String API = "J7W39ZEOM03DO7AQ";                                                    // Write API key (dal ThingSpeak channel)
String APIR = "SDJC7W09UQBOMNJD";
String HOST = "api.thingspeak.com";
String PORT = "80";
String CHANNEL = "1397613";
int countTimeCommand; 
String message;
String messager;
String buffer;

int X1=6;         // variabili di prova
int X2=7;
int X3=8;

void setup() {
  Serial.begin(9600);     // comunica via seriale (0, 1) : NOTA: durante il caricamento script stacca i pin 0 e 1 (ricollegali dopo)
  esp8266.begin(115200);

  sendCommand("AT",5,"OK");
  sendCommand("AT+CWMODE=1",5,"OK");
  sendCommand("AT+CWJAP=\""+AP+"\",\""+PASS+"\"",20,"OK");  //connessione al router wifi
}

void loop() {
  
  message="GET /update?api_key="+API+"&field1="+X1+"&field2="+X2+"&field3="+X3;
  messager = "GET /channels/"+CHANNEL+"/feeds.json?api_key="+APIR+"&results=2";

  sendCommand("AT+CIPMUX=1",5,"OK");
  sendCommand("AT+CIPSTART=0,\"TCP\",\""+HOST+"\","+PORT,15,"OK");
  sendCommand("AT+CIPSTO=10",5,"OK");
  sendCommand("AT+CIPSEND=0,"+String(message.length()+4),4,">");
  esp8266.println(message);
  sendCommand("AT+CIPCLOSE=0",5,"OK");
  Serial.println("Writing done!");

  
  //LETTURA
  sendCommand("AT+CIPMUX=1",5,"OK");
  sendCommand("AT+CIPSTART=0,\"TCP\",\""+HOST+"\","+PORT,15,"OK");
  sendCommand("AT+CIPSTO=10",5,"OK");
  sendCommand("AT+CIPSEND=0,"+String(messager.length()+4),4,">");
  esp8266.println(messager);
  sendCommand("AT+CIPCLOSE=0",5,"OK");
  buffer = esp8266.read();
  Serial.println("Reading done!");
  Serial.println(buffer);
  
  delay(15000);           // ricorda che su ThingSpeak non devono passare meno di 15 s tra un invio e l'altro
     
}

void sendCommand(String command,int maxTime,char readReplay[])    // funzione di invio comando tra arduino e l'esp
{
  while(countTimeCommand<maxTime)
  {
    esp8266.println(command);
    if(esp8266.find(readReplay))
    {
      break;
    }
    countTimeCommand++;
  }
  countTimeCommand=0;
}

I tried to create a buffer to store the answer from the server and printed it on my serial monitor pc, but all I receive is the number 13, which I think are the first two digits of my channel number on ThingSpeak. What should I do?

Software serial isn't reliable at that speed, try 38400 or less.

Serial.read gets one character, use getStringUntil perhaps.

Ok I'll change the speed to 38400. For the reading part I get the error:
'class SoftwareSerial' has no member named 'getStringUntil'; did you mean 'readStringUntil'?
Thank you for all you have done to help me.

Yes - apparently I misremembered the function name.

With the readStringUntil method I get nothing printed on the serial monitor. I honestly don't know what to do at this point.

Post your latest code.

You could read characters from the esp one at a time and print them to serial. Just use a while(true) loop to do it so you can be sure you're getting everything and then you can devise something to read properly once you know what you're getting.

#include <SoftwareSerial.h>

SoftwareSerial esp8266(2,3);

String AP = "Telefono";                                                  // WiFi NAME
String PASS = "caccacca";                                                  // WiFi PASSWORD
String API = "J7W39ZEOM03DO7AQ";                                                    // Write API key (dal ThingSpeak channel)
String APIR = "SDJC7W09UQBOMNJD";
String HOST = "api.thingspeak.com";
String PORT = "80";
String CHANNEL = "1397613";
int countTimeCommand; 
String message;
String messager;
String buffer;

int X1=6;         // variabili di prova
int X2=7;
int X3=8;

void setup() {
  Serial.begin(9600);     // comunica via seriale (0, 1) : NOTA: durante il caricamento script stacca i pin 0 e 1 (ricollegali dopo)
  esp8266.begin(38400);

  sendCommand("AT",5,"OK");
  sendCommand("AT+CWMODE=1",5,"OK");
  sendCommand("AT+CWJAP=\""+AP+"\",\""+PASS+"\"",20,"OK");  //connessione al router wifi
}

void loop() {
  
  message="GET /update?api_key="+API+"&field1="+X1+"&field2="+X2+"&field3="+X3;
  messager = "GET /channels/"+CHANNEL+"/feeds.json?api_key="+APIR+"&results=2";
  

  sendCommand("AT+CIPMUX=1",5,"OK");
  sendCommand("AT+CIPSTART=0,\"TCP\",\""+HOST+"\","+PORT,15,"OK");
  sendCommand("AT+CIPSTO=10",5,"OK");
  sendCommand("AT+CIPSEND=0,"+String(message.length()+4),4,">");
  esp8266.println(message);
  sendCommand("AT+CIPCLOSE=0",5,"OK");
  Serial.println("Writing done!");

  
  //LETTURA
  sendCommand("AT+CIPMUX=1",5,"OK");
  sendCommand("AT+CIPSTART=0,\"TCP\",\""+HOST+"\","+PORT,15,"OK");
  sendCommand("AT+CIPSTO=10",5,"OK");
  sendCommand("AT+CIPSEND=0,"+String(messager.length()+4),4,">");
  esp8266.println(messager);
  sendCommand("AT+CIPCLOSE=0",5,"OK");
 
  buffer = esp8266.readStringUntil('\r');
  Serial.println("Reading done!");
  Serial.println(buffer);
  
  
  delay(15000);           // ricorda che su ThingSpeak non devono passare meno di 15 s tra un invio e l'altro
     
}

void sendCommand(String command,int maxTime,char readReplay[])    // funzione di invio comando tra arduino e l'esp
{
  while(countTimeCommand<maxTime)
  {
    esp8266.println(command);
    if(esp8266.find(readReplay))
    {
      break;
    }
    countTimeCommand++;
  }
  countTimeCommand=0;
}

This is my latest code. Feel free to edit it if you spot any mistake. I don't know how to implement the loop you were talking about. Thank you again

Where you have this:

  buffer = esp8266.readStringUntil('\r');
  Serial.println("Reading done!");
  Serial.println(buffer);
  delay(15000);           // ricorda che su ThingSpeak non devono passare meno di 15 s tra un invio e l'altro

Try:

  while(true)
    {
    if(esp8266.available())
      {
      char ch;
      ch=esp8266.read();
      Serial.print(ch);
      }
    }

I tried with your code.

#include <SoftwareSerial.h>

SoftwareSerial esp8266(2,3);

String AP = "Telefono";                                                  // WiFi NAME
String PASS = "caccacca";                                                  // WiFi PASSWORD
String API = "J7W39ZEOM03DO7AQ";                                                    // Write API key (dal ThingSpeak channel)
String APIR = "SDJC7W09UQBOMNJD";
String HOST = "api.thingspeak.com";
String PORT = "80";
String CHANNEL = "1397613";
int countTimeCommand; 
String message;
String messager;
String buffer;

int X1=6;         // variabili di prova
int X2=7;
int X3=8;

void setup() {
  Serial.begin(9600);     // comunica via seriale (0, 1) : NOTA: durante il caricamento script stacca i pin 0 e 1 (ricollegali dopo)
  esp8266.begin(38400);

  sendCommand("AT",5,"OK");
  sendCommand("AT+CWMODE=1",5,"OK");
  sendCommand("AT+CWJAP=\""+AP+"\",\""+PASS+"\"",20,"OK");  //connessione al router wifi
}

void loop() {
  
  message="GET /update?api_key="+API+"&field1="+X1+"&field2="+X2+"&field3="+X3;
  messager = "GET /channels/"+CHANNEL+"/feeds.json?api_key="+APIR+"&results=2";
  

  sendCommand("AT+CIPMUX=1",5,"OK");
  sendCommand("AT+CIPSTART=0,\"TCP\",\""+HOST+"\","+PORT,15,"OK");
  sendCommand("AT+CIPSTO=10",5,"OK");
  sendCommand("AT+CIPSEND=0,"+String(message.length()+4),4,">");
  esp8266.println(message);
  sendCommand("AT+CIPCLOSE=0",5,"OK");
  Serial.println("Writing done!");

  
  //LETTURA
  sendCommand("AT+CIPMUX=1",5,"OK");
  sendCommand("AT+CIPSTART=0,\"TCP\",\""+HOST+"\","+PORT,15,"OK");
  sendCommand("AT+CIPSTO=10",5,"OK");
  sendCommand("AT+CIPSEND=0,"+String(messager.length()+4),4,">");
  esp8266.println(messager);
  sendCommand("AT+CIPCLOSE=0",5,"OK");

Serial.println("Starting to read...");
  
 /*
  buffer = esp8266.readStringUntil('\r');
  Serial.println("Reading done!");
  Serial.println(buffer);
  */
  while(true)
    {
    if(esp8266.available())
      {
      char ch;
      ch=esp8266.read();
      Serial.print(ch);
      }
    }
  delay(15000);           // ricorda che su ThingSpeak non devono passare meno di 15 s tra un invio e l'altro
     
}

void sendCommand(String command,int maxTime,char readReplay[])    // funzione di invio comando tra arduino e l'esp
{
  while(countTimeCommand<maxTime)
  {
    esp8266.println(command);
    if(esp8266.find(readReplay))
    {
      break;
    }
    countTimeCommand++;
  }
  countTimeCommand=0;
}

The last thing the serial printed is the "Starting to read..." line. After that it doesn't print anything else. I even tried to comment out the "if" statement and it printed an infinite list of "?"
Basically what I think is happening is that the condition available() is never satisfied.

In that case, I suspect that the API request is invalid and there is nothing returned to be read. You could print what you're sending to the API to serial to check your syntax.

I did it. The API request should be "GET https://api.thingspeak.com/channels/1397613/feeds.json?api_key=SDJC7W09UQBOMNJD&results=2". I printed it on the serial and it is correct. I even tried to add the hostname (api.thingspeak.com), but it does not work.

Does that work from a browser?

Yes, it does. If you click on the link you can see my variables.

It might be sendCommand. You're searching through what is returned looking for '>'. Maybe that's skipping over the data from the API.

Maybe move the infinite while loop up under the print of messager and see what you get.