uploading data to thingspeak without using delay()

Hello all. I'm writing a code to upload data (three fields) to thingspeak. Everything works well but i'm worried that i have too many delays in the code which slows down every other thing the code is doing like printing to lcd and others. Once the method is running, everything other thing in the code is on stand still. I'm sure this isn't a good technique. I learnt about using millis() instead of delay() but can't seem to understand using that when i have several delays. I need help to ditch all the delays altogether. Please for some five minutes of your time to help me out, i'll be infinitely grateful.

void uploadData(){

 if (gsm.available())
  
  gsm.println("AT+CGATT?");
 delay(1000);

 gsm.println("AT+CIPSHUT");
 delay(1000);

 gsm.println("AT+CIPSTATUS");
 delay(2000);

 gsm.println("AT+CIPMUX=0");
 delay(2000);

 gsm.println("AT+CSTT=\"web.gprs.mtnet.net\"");//start task and setting the APN,
 delay(1000);

  gsm.println("AT+CIICR");//bring up wireless connection
 delay(2000);
 
 gsm.println("AT+CIFSR");//get local IP adress
 delay(2000);

 gsm.println("AT+CIPSPRT=0");
 delay(2000);

 
 gsm.println("AT+CIPSTART=\"TCP\",\"api.thingspeak.com\",\"80\"");//start up the connection
 delay(4000);

 gsm.println("AT+CIPSEND");//begin send data to remote server
 delay(4000);
  
 String str="GET https://api.thingspeak.com/update?api_key=xxxxxxxxxxxxxxxxxx &field1=" + String(Voltage) +"&field2="+String(frequency) +"&field3="+String(current);
 
 gsm.println(str);//begin send data to remote server
 
 delay(4000);
  
 gsm.println((char)26);//sending
 delay(5000);//waitting for reply, important! the time is base on the condition of internet 
 gsm.println();

 gsm.println("AT+CIPSHUT");//close the connection
 delay(100);

 
}

You can do something like this:

unsigned long DelayRequired=0;

void uploadData()
{
static int CurrentStep=0;
  
static int CurrentStep=0;
if(millis()-PrevMillis > DelayRequired)
  {
  PrevMillis=millis();
  switch(CurrentStep)  
    {
    case 0:
      gsm.println("AT+CGATT?");
      DelayRequired=1000;
      break;
    case 1:
      gsm.println("AT+CIPSHUT");
      DelayRequired=1000;
      break;
    case 2:
      gsm.println("AT+CIPSTATUS");
      DelayRequired=2000;
      break;
    // etc etc  
    }
  CurrentStep++;
  }
}

Keep calling uploadData from loop. Each time it's called, it checks the time to see whether it's ready for the next step. As written, it will only work once and there's no mechanism to tell you when it's done. All it does is illustrate the principle of using millis to sequence some steps. Technically, it's a very basic state machine q.v.

Thank you @wildbill, I'm getting to realize the difference between a working code and an optimally functional one. I had fun playing with what you sent me. Unfortunately i couldn't get it to run more than once even after calling it inside the loop function. Please what do i need to change or add to make the code run continuously

Make CurrentStep global. In loop, check to see whether it's greater than the number of the last step in your switch. If it is, set it zero again.

I implemented your advice in a hypothetical case and it worked well. I will try to implement it in my code and revert. Thank you

How frequently can you upload data to Thingspeak?

I upload to thingspeak every minute. I have attached what my code looks like. When i use it as a standalone code, it worked after i tweaked it a little bit but when i integrated it into my work with several other methods such as one sending email, text message and a whole lot of other things the upload() method that was suppose to send data to thingspeak did not even run let alone upload anything to things speak.

#include <SoftwareSerial.h>
SoftwareSerial gsm(9, 10); // tx is connected to pin 9 and rx is to pin 10
static unsigned long DelayRequired=0;
static unsigned long PrevMillis =0;
static int CurrentStep=0;

int mainsVoltage = 0;
int inverterVoltage = 0;
float frequency = 0.0;

  
void uploadData()
{
if(millis()-PrevMillis > DelayRequired)
  {
  PrevMillis=millis();
  switch(CurrentStep) 
    {
    case 0:
      if (gsm.available())
      ShowSerialData();
      gsm.println("AT+CGATT?");
      DelayRequired=2000;
      break;
    case 1:
      ShowSerialData();
      gsm.println("AT+CIPSHUT");
      DelayRequired=2000;
      break;
    case 2:
      ShowSerialData();
      gsm.println("AT+CIPSTATUS");
      DelayRequired=3000;
      break;
    case 3:
      ShowSerialData();
      gsm.println("AT+CIPMUX=0");
      DelayRequired=2000;
      break;
    case 4:
      ShowSerialData();
      gsm.println("AT+CSTT=\"web.gprs.mtnnigeria.net\"");//start task and setting the APN
      DelayRequired=2000;
      break;
    case 5:
      ShowSerialData();
      gsm.println("AT+CIICR");//bring up wireless connection
      DelayRequired=2000;
      break;
    case 6:
      ShowSerialData();
      gsm.println("AT+CIFSR");//get local IP adress
      DelayRequired=2000;
      break;
    case 7:
      ShowSerialData();
      gsm.println("AT+CIPSPRT=0");
      DelayRequired=2000;
      break;
    case 8:
      ShowSerialData();
      gsm.println("AT+CIPSTART=\"TCP\",\"api.thingspeak.com\",\"80\"");//start up the connection
      DelayRequired=4000;
      break;
    case 9:
      ShowSerialData();
      gsm.println("AT+CIPSEND");//begin send data to remote server
      DelayRequired=4000;
      break;
    case 10:
      ShowSerialData();
      String str="GET https://api.thingspeak.com/update?api_key=2TADWYFAJQJW76AN &field1=" + String(mainsVoltage) +"&field2="+String(frequency) +"&field3="+String(inverterVoltage);
     // delay(1000);
      gsm.println(str);//begin send data to remote server
      DelayRequired=4000;
      //break;
    case 11:
      ShowSerialData();
      //delay(1000);
      gsm.println((char)26);//sending
      DelayRequired=5000;
      break;
    case 12:
      gsm.println();
      ShowSerialData();
      gsm.println("AT+CIPSHUT");//close the connection
      DelayRequired=2000;
      break;
    }
  CurrentStep++;
  }
}

void ShowSerialData()
{
  while(gsm.available()!=0)
  Serial.write(gsm.read());
  delay(1000); 
  
}
void setup() {  
  Serial.begin(9600);
  gsm.begin(9600);
  if (gsm.available())
  ShowSerialData();
     gsm.println("AT");
     delay(500);
     
     //gsm.println("AT+CPIN?");
     //delay(5000);
    ShowSerialData();
     gsm.println("AT+CREG?");
     delay(500); 
}
void loop() {
  //Serial.println("inside loop now");
  mainsVoltage = 230;
 inverterVoltage = 230;
 frequency = 50.0;
  if(CurrentStep > 12)  CurrentStep = 0;
  uploadData();
   
  }

That doesn't compile for me. Also, there's a break commented out which I can't see a reason for. In case 10 I put the break back and put braces around the code. Now it compiles at least.

i commented out the break in case 10 because it doesn't upload to thingspeak until i did. It just keep sending command without getting any response from the gsm module

What you had, with the break enabled looks functionally equivalent to the original code with delays, except that you added calls to ShowSerialData which itself has a delay in it.

As a test, I would either remove that delay or comment out all the calls to ShowSerialData.

@wildbill, once i remove that break at case 10, the whole code stops running at case 8. What i noticed is once case 8 runs other cases runs without listening for any response from the gsm module. If i comment out the break, everything works well but once you use the code with other methods running it doesn't work again. it's really funny. Can you help me make sense of this.

Post the latest code you're using.

This is what my main loop looks like. I have already posted the upload() method that is supposed to send data to thingspeak.

void loop() {
 calFrequency();  
 calMainVoltage();
 calInverterVoltage(); 
 
 //if (millis() - lastConnectionTime > postingInterval) {
  if(CurrentStep > 12)  CurrentStep = 0;
  uploadData(); 
  //  }
    ///////////////////////////
  Serial.println(mainsVoltage);
  Serial.println(inverterVoltage);
  Serial.println(frequency);
  /////////////////////////////
  lcd.clear();
   lcd.setCursor(0,0);
   lcd.print("GRD ");
   lcd.print(mainsVoltage);
   lcd.print("V ");
   lcd.print(frequency);
   lcd.print("Hz");
   lcd.setCursor(0, 1);
   lcd.print("INV ");
   lcd.print(inverterVoltage);
   lcd.print("V ");
   lcd.setCursor(9,1);
   lcd.print("Net ");
  if(sendATcommand("AT+CGATT=1\r\n", "OK\r\n", TIMEOUT)==1)
   {
   lcd.setCursor(13,1);
   lcd.print("OK!");
   } else
   {

    lcd.setCursor(13,1);
    lcd.print("NA!");
   }
  delay(100);

if (millis() - 0 > postingInterval2) {  
allSms();
allEmail();  
}
}
////////////////////////////////////////////////////////////////////end main loop

May be there is a better and easy way of going about this. I found this piece of code which is even more popular and efficient. It will at least not tie down my program like the other one. The only problem is that its sending only one sensor value to thingspeak whereas mine is sending three sensor values. please what will i have to change in the code to be able to send three sensor values rather than only one that the code was initially written to send. Thanks for your help

#include <SoftwareSerial.h>
 
//SIM800 TX is connected to Arduino D8
#define SIM800_TX_PIN 9
 
//SIM800 RX is connected to Arduino D7
#define SIM800_RX_PIN 10
 
//Create software serial object to communicate with SIM800
SoftwareSerial serialSIM800(SIM800_TX_PIN,SIM800_RX_PIN);

#define TIMEOUT 30000

int8_t answer;

int onModulePin = 13;

char aux_str[100];

int x = 0;

int attempts;

char apn[] = "internet.movistar.ve";

//char url[ ]="api.thingspeak.com/update?api_key=PHRFH37I50UK9MGF&field1=20.50";
char url[ ]="api.thingspeak.com/update?api_key=2TADWYFAJQJW76AN&field1=";


unsigned long lastConnectionTime = 0;         // last time you connected to the server, in milliseconds
const unsigned long postingInterval = 15000L; // delay between updates, in milliseconds


void setup()
{
  
  pinMode(onModulePin, OUTPUT);
  
  //Begin serial comunication with Arduino and Arduino IDE (Serial Monitor)
  Serial.begin(9600);
  while(!Serial);
   
  //Being serial communication with Arduino and SIM800
  serialSIM800.begin(9600);
  delay(1000);
   
  Serial.println("Starting...");
  
  power_on();

  delay(3000);
  
  //Serial.println("AT+HTTPPARA=\"URL\",\"www.castillolk.com.ve/WhiteList.txt\"\r\n");
  
  while( (sendATcommand("AT+CREG?\r\n", "+CREG: 0,1\r\n", 500) || 
            sendATcommand("AT+CREG?\r\n", "+CREG: 0,5\r\n", 500)) == 0 );

  /* sendATcommand("AT+SAPBR=3,1,\"Contype\",\"GPRS\"\r\n", "OK\r\n", TIMEOUT);//sets Contype
  snprintf(aux_str, sizeof(aux_str), "AT+SAPBR=3,1,\"APN\",\"%s\"\r\n", apn);//sets APN
  sendATcommand(aux_str, "OK\r\n", TIMEOUT); */
  
  connectToNetwork();
  initHTTPSession();
  HTTPRequest();
  
}
 
void loop() 
{
  // if 15 seconds have passed since your last connection,
  // then connect again and send data
  if (millis() - lastConnectionTime > postingInterval) {
    HTTPRequest();
  }
}

/////////////////////////////////////////////////////////
int8_t sendATcommand(const char* ATcommand, const char* expected_answer1, unsigned int timeout) {

  uint8_t x = 0,  answer = 0;
  char response[100];
  unsigned long previous;

  memset(response, '\0', 100);    // Initialize the string

  delay(100);

  while (serialSIM800.available())
  { //Cleans the input buffer
    serialSIM800.read();
  }



  Serial.println(ATcommand);    // Prints the AT command
  serialSIM800.write(ATcommand); // Sends the AT command


  x = 0;
  previous = millis();

  // this loop waits for the answer
  do
  {
    ////if (Serial.available() != 0) {
    if (serialSIM800.available() != 0)
  {
      ////response[x] = Serial.read();
      response[x] = serialSIM800.read();
      x++;
      // check if the desired answer is in the response of the module
      if (strstr(response, expected_answer1) != NULL)
      {
        answer = 1;
      }
    }
    // Waits for the asnwer with time out
  }
  while ((answer == 0) && ((millis() - previous) < timeout));

  return answer;
}

/////////////////////////////////////////////////////////
void power_on()
{

  uint8_t answer = 0;

  Serial.println("On Power_on...");

  // checks if the module is started
  answer = sendATcommand("AT\r\n", "OK\r\n", TIMEOUT);
  if (answer == 0)
  {
    // power on pulse
    digitalWrite(onModulePin, HIGH);
    delay(3000);
    digitalWrite(onModulePin, LOW);

    // waits for an answer from the module
    while (answer == 0)
  {
      // Send AT every two seconds and wait for the answer
      answer = sendATcommand("AT\r\n", "OK\r\n", TIMEOUT);
      Serial.println("Trying connection with module...");
    }
  }
}

/////////////////////////////////////////////////////////
void restartPhoneActivity()
{
  do
  {
    sendATcommand("AT+CFUN=0\r\n", "OK\r\n", TIMEOUT);
    delay(2000);
    answer = sendATcommand("AT+CFUN=1\r\n", "Call Ready\r\n", TIMEOUT);
  }while(answer == 0);
}
/////////////////////////////////////////////////////////
void connectToNetwork()
{
  sendATcommand("AT+SAPBR=3,1,\"Contype\",\"GPRS\"\r\n", "OK\r\n", TIMEOUT);//sets Contype
  snprintf(aux_str, sizeof(aux_str), "AT+SAPBR=3,1,\"APN\",\"%s\"\r\n", apn);//sets APN
  sendATcommand(aux_str, "OK\r\n", TIMEOUT);
  attempts = 0;//tries 3 times or gets on the loop until sendATcommand != 0
  while (sendATcommand("AT+SAPBR=1,1\r\n", "OK\r\n", TIMEOUT) == 0)
    {
    delay(5000);
    attempts = attempts + 1;
    if(attempts > 2)
    {
      restartPhoneActivity();
      attempts = 0;
    }
    } 
}
/////////////////////////////////////////////////////////
void initHTTPSession()
{
  while (sendATcommand("AT+HTTPINIT\r\n", "OK\r\n", TIMEOUT) == 0)
    {
    restartPhoneActivity();
    connectToNetwork();
   }
}
/////////////////////////////////////////////////////////
void HTTPRequest()
{

  ////snprintf(aux_str, sizeof(aux_str), "AT+HTTPPARA=\"URL\",\"%s\"\"%f\"\r\n", url, light);
  float light = readLDR();
  char sensorValue[6];
  dtostrf(light,5,2,sensorValue);
  snprintf(aux_str, sizeof(aux_str), "AT+HTTPPARA=\"URL\",\"%s\%s\"\r\n", url, sensorValue);
  sendATcommand(aux_str, "OK\r\n", TIMEOUT);
  delay(3000);
  attempts = 0;//tries 3 times or gets on the loop until sendATcommand != 0
  while (sendATcommand("AT+HTTPACTION=0\r\n", "+HTTPACTION: 0,200,", TIMEOUT) == 0)
    {
    delay(5000);
    attempts = attempts + 1;
    if(attempts > 2)
    {
      sendATcommand("AT+SAPBR=0,1\r\n", "OK\r\n", 2 * TIMEOUT);
      sendATcommand("AT+HTTPTERM\r\n", "OK\r\n", TIMEOUT);
      restartPhoneActivity();
      connectToNetwork();
      initHTTPSession();
      ////snprintf(aux_str, sizeof(aux_str), "AT+HTTPPARA=\"URL\",\"%s\"\r\n", url);
      light = readLDR();
      char sensorValue[6];
      dtostrf(light,5,2,sensorValue);
      snprintf(aux_str, sizeof(aux_str), "AT+HTTPPARA=\"URL\",\"%s\%s\"\r\n", url, sensorValue);
      sendATcommand(aux_str, "OK\r\n", TIMEOUT);
      attempts = 0;
    }
    }
  Serial.println("Successfully uploaded");
  // note the time that the connection was made
    lastConnectionTime = millis();
  
}
/////////////////////////////////////////////////////////
float readLDR()
{
  //read the input on analog pin 0:
  int sensorValue = analogRead(A0);
  //Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float voltage = sensorValue * (5.0 / 1023.0);
  // print out the value you read:
  Serial.println(voltage);
  return voltage;
}