Can´t connect to MySQL using sprintf

Hello guys,

I need to comunicate with MySQL to store a variable from arduino. When I use just a Char statement I can get it to work, but when I use sprintf to create a statement from a variable, the arduino stucks trying to connect to MySQL. Can anyone help to solve this problem?

The codes are shown bellow and the serial responses are attached. Any help is apreciated, thanks in advance!

This code works perfectly:

#include "Ultrasonic.h"
#include <SPI.h>
#include <Ethernet.h>
#include <MySQL_Connection.h>
#include <MySQL_Cursor.h>

byte mac_addr[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

IPAddress server_addr(192,168,10,135);  // IP of the MySQL *server* here
char user[] = "MyUser";              // MySQL user login username
char password[] = "MyPassword";        // MySQL user login password

// Sample query
char INSERT_SQL[] = "INSERT INTO rafael.eventos (nivel,estado) VALUES (1,'teste')";


EthernetClient clientEmail;
EthernetClient client;
MySQL_Connection conn((Client *)&client);



int    HTTP_PORT   = 80;
String HTTP_METHOD = "GET";
char   HOST_NAME[] = "maker.ifttt.com";
String PATH_NAME   = "/trigger/problemaCaixa/with/key/f9WuiRFn8Dj4ufPo5hgKMIgYfnio3Vu9biAIEmYr-Ni"; // change your EVENT-NAME and YOUR-KEY
String queryString = "?value1=26&value2=70";


void setup() {
  Serial.begin(9600);
  while (!Serial); // wait for serial port to connect
  Serial.println("Connecting...");
  if (Ethernet.begin(mac_addr)==0){
    Serial.println("Failed to configure Ethernet using DHCP");
   }
  
  Serial.println(Ethernet.localIP());
  
  
}


void loop() {
  
  delay(2000);
  sendData();
  email();
}






void email(){
    // connect to web server on port 80:
  if(clientEmail.connect(HOST_NAME, HTTP_PORT)) {
    // if connected:
    Serial.println("Connected to server");
    // make a HTTP request:
    // send HTTP header
    clientEmail.println("GET " + PATH_NAME + queryString + " HTTP/1.1");
    clientEmail.println("Host: " + String(HOST_NAME));
    clientEmail.println("Connection: close");
    clientEmail.println(); // end HTTP header

    while(clientEmail.connected()) {
      if(clientEmail.available()){
        // read an incoming byte from the server and print it to serial monitor:
        char c = clientEmail.read();
        Serial.print(c);
      }
    }

    // the server's disconnected, stop the client:
    clientEmail.stop();
    Serial.println();
    Serial.println("disconnected");
  } else {// if not connected:
    Serial.println("connection failed");
  }
}






void sendData(){
  if (conn.connect(server_addr, 3306, user,password)) {
    Serial.println("Recording data.");
  }
  else
    Serial.println("Connection failed.");

  // Initiate the query class instance
  MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
  // Execute the query
  cur_mem->execute(INSERT_SQL);
  // Note: since there are no results, we do not need to read any data
  // Deleting the cursor also frees up memory used
  delete cur_mem;
  conn.close();  
  client.stop();
}

This code does not work:

#include "Ultrasonic.h"
#include <SPI.h>
#include <Ethernet.h>
#include <MySQL_Connection.h>
#include <MySQL_Cursor.h>

byte mac_addr[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

IPAddress server_addr(192,168,10,135);  // IP of the MySQL *server* here
char user[] = "domoticaSamsung";              // MySQL user login username
char password[] = "Rafa#rafa1";        // MySQL user login password

// Sample query
char bigBuf[100] = "";
char INSERT_SQL[] = "INSERT INTO rafael.eventos (nivel,estado) VALUES (%d,%s);";
int media =5;

EthernetClient clientEmail;
EthernetClient client;
MySQL_Connection conn((Client *)&client);



int    HTTP_PORT   = 80;
String HTTP_METHOD = "GET";
char   HOST_NAME[] = "maker.ifttt.com";
String PATH_NAME   = "/trigger/problemaCaixa/with/key/f9WuiRFn8Dj4ufPo5hgKMIgYfnio3Vu9biAIEmYr-Ni"; // change your EVENT-NAME and YOUR-KEY
String queryString = "?value1=26&value2=70";


void setup() {
  Serial.begin(9600);
  while (!Serial); // wait for serial port to connect
  Serial.println("Connecting...");
  if (Ethernet.begin(mac_addr)==0){
    Serial.println("Failed to configure Ethernet using DHCP");
   }
  
  Serial.println(Ethernet.localIP());
  
  
}


void loop() {
  
  delay(2000);
  sprintf(bigBuf, INSERT_SQL, media,"'diminuindo'");
  sendData();
  email();
}






void email(){
    // connect to web server on port 80:
  if(clientEmail.connect(HOST_NAME, HTTP_PORT)) {
    // if connected:
    Serial.println("Connected to server");
    // make a HTTP request:
    // send HTTP header
    clientEmail.println("GET " + PATH_NAME + queryString + " HTTP/1.1");
    clientEmail.println("Host: " + String(HOST_NAME));
    clientEmail.println("Connection: close");
    clientEmail.println(); // end HTTP header

    while(clientEmail.connected()) {
      if(clientEmail.available()){
        // read an incoming byte from the server and print it to serial monitor:
        char c = clientEmail.read();
        Serial.print(c);
      }
    }

    // the server's disconnected, stop the client:
    clientEmail.stop();
    Serial.println();
    Serial.println("disconnected");
  } else {// if not connected:
    Serial.println("connection failed");
  }
}






void sendData(){
  if (conn.connect(server_addr, 3306, user,password)) {
    Serial.println("Recording data.");
  }
  else
    Serial.println("Connection failed.");

  // Initiate the query class instance
  MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
  // Execute the query
  cur_mem->execute(bigBuf);
  // Note: since there are no results, we do not need to read any data
  // Deleting the cursor also frees up memory used
  delete cur_mem;
  conn.close();  
  client.stop();
}

How much SRAM memory do you have left when compiling? Having allocated the. 200 extra bytes fro bigbuf might get you in challenging zone at run time

J-M-L:
How much SRAM memory do you have left when compiling? Having allocated the. 200 extra bytes fro bigbuf might get you in challenging zone at run time

Thats what I get when compiling:

O sketch usa 21824 bytes (67%) de espaço de armazenamento para programas. O máximo são 32256 bytes.
Variáveis globais usam 1348 bytes (65%) de memória dinâmica, deixando 700 bytes para variáveis locais. O máximo são 2048 bytes.

I think I´m using 65% of the SRAM.

Have you tried printing bigBuf after the sprintf() ?
Does it look as you expect ?

Indeed printing the request would be a first step but the sprintf code does not look bad (you could make the format string à const char*)

By the way forgot to suggest you should edit and remove all the credentials you posted publicly in the Previous posts

700 bytes should be OK I guess unless you have big dynamic allocation stuff going on

ÉDIT:
Just noticed you have a trailing ; in the second request which you don’t have in the first.
1st: INSERT INTO rafael.eventos (nivel,estado) VALUES (1,'teste')
2nd: INSERT INTO rafael.eventos (nivel,estado) VALUES (5,'diminuindo');

Some database systems require a semicolon at the end of each SQL statement. Semicolon is the standard way to separate each SQL statement in database systems that allow more than one SQL statement to be executed in the same call to the server. Maybe your DB is waiting for a second statement to start a transaction

UKHeliBob:
Have you tried printing bigBuf after the sprintf() ?
Does it look as you expect ?

Yes, I have printed and it does look like expected.
I tried runing without the email function and it worked (only sprintf and sendData in loop). That´s weird. It looks like I cant add more stuff to loop.

J-M-L:
Indeed printing the request would be a first step but the sprintf code does not look bad (you could make the format string à const char*)

By the way forgot to suggest you should edit and remove all the credentials you posted publicly in the Previous posts

700 bytes should be OK I guess unless you have big dynamic allocation stuff going on

ÉDIT:
Just noticed you have a trailing ; in the second request which you don’t have in the first.
1st: INSERT INTO rafael.eventos (nivel,estado) VALUES (1,'teste')
2nd: INSERT INTO rafael.eventos (nivel,estado) VALUES (5,'diminuindo');

Some database systems require a semicolon at the end of each SQL statement. Semicolon is the standard way to separate each SQL statement in database systems that allow more than one SQL statement to be executed in the same call to the server. Maybe your DB is waiting for a second statement to start a transaction

Yeah, indeed! But I tried with and without the semicolon and got the same result. When I have a syntax problem I get an "Syntax error" from MySQL.

I dont know what else I could test. this error doesn´t make sense to me.

I tried runing without the email function and it worked (only sprintf and sendData in loop). That´s weird. It looks like I cant add more stuff to loop.

That seems to confirm the hypothesis of lack of SRAM. Dig into your email library to see what’s being done. If large buffers are allocated then that’s probably the issue

Do you have an arduino MEGA you could try the sketch on ?

J-M-L:
That seems to confirm the hypothesis of lack of SRAM. Dig into your email library to see what’s being done. If large buffers are allocated then that’s probably the issue

Do you have an arduino MEGA you could try the sketch on ?

I do not have a arduino MEGA... I am going to try to send email through PHP and keep the arduino just for storing data to database, this could solve my problem for now. In the future I will try again with MEGA to confirm the lack of SRAM.
Thank you for your help!

do you need to use an escape sequence, ' for the single quotes?

Storing as much as possible in PROGMEM, and removing the use of String, leaves plenty of RAM:
(note I have removed the personal information in user, password, and PATH_NAME, you will need to replace those)

#include "Ultrasonic.h"
#include <SPI.h>
#include <Ethernet.h>
#include <MySQL_Connection.h>
#include <MySQL_Cursor.h>

byte mac_addr[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

IPAddress server_addr(192,168,10,135);  // IP of the MySQL *server* here
char user[] = "removed";              // MySQL user login username
char password[] = "removed";        // MySQL user login password

// Sample query
char bigBuf[100] = "";
const char INSERT_SQL[] PROGMEM = "INSERT INTO rafael.eventos (nivel,estado) VALUES (%d,%S);";
//note - capital S refers to char array stored in PROGMEM
int media =5;

EthernetClient clientEmail;
EthernetClient client;
MySQL_Connection conn((Client *)&client);



int    HTTP_PORT   = 80;
const char HTTP_METHOD[] = "GET";
const char   HOST_NAME[] = "maker.ifttt.com";
const char PATH_NAME[] PROGMEM = "removed"; // change your EVENT-NAME and YOUR-KEY
const char queryString[] PROGMEM = "?value1=26&value2=70";


void setup() {
  Serial.begin(9600);
  while (!Serial); // wait for serial port to connect
  Serial.println(F("Connecting..."));
  //if (Ethernet.begin(mac_addr)==0){
  //  Serial.println(F("Failed to configure Ethernet using DHCP"));
  // }
 
  //Serial.println(Ethernet.localIP());
 
}


void loop() {
 
  delay(2000);
  sprintf_P(bigBuf, INSERT_SQL, media, PSTR("'diminuindo'"));
  sendData();
  email();
}






void email(){
    // connect to web server on port 80:
  if(clientEmail.connect(HOST_NAME, HTTP_PORT)) {
    // if connected:
    Serial.println(F("Connected to server"));
    // make a HTTP request:
    // send HTTP header
    //clientEmail.println("GET " + PATH_NAME + queryString + " HTTP/1.1");
    char buff[sizeof("GET ") + sizeof(PATH_NAME) + sizeof(queryString) + sizeof(" HTTP/1.1")]; //let compiler calculate size of buffer
    strcpy_P(buff, PSTR("GET "));
    strcat_P(buff, PATH_NAME);
    strcat_P(buff, queryString);
    strcat_P(buff, PSTR(" HTTP/1.1"));
    clientEmail.println(buff);
    //clientEmail.println("Host: " + String(HOST_NAME));
    strcpy_P(buff, PSTR("Host: "));
    strcat(buff, HOST_NAME);
    clientEmail.println(buff);
    clientEmail.println(F("Connection: close"));
    clientEmail.println(); // end HTTP header

    while(clientEmail.connected()) {
      if(clientEmail.available()){
        // read an incoming byte from the server and print it to serial monitor:
        char c = clientEmail.read();
        Serial.print(c);
      }
    }

    // the server's disconnected, stop the client:
    clientEmail.stop();
    Serial.println();
    Serial.println(F("disconnected"));
  } else {// if not connected:
    Serial.println(F("connection failed"));
  }
}






void sendData(){
  if (conn.connect(server_addr, 3306, user,password)) {
    Serial.println(F("Recording data."));
  }
  else
    Serial.println(F("Connection failed."));

  // Initiate the query class instance
  MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
  // Execute the query
  cur_mem->execute(bigBuf);
  // Note: since there are no results, we do not need to read any data
  // Deleting the cursor also frees up memory used
  delete cur_mem;
  conn.close(); 
  client.stop();
}

Would be a bit simpler if the Ethernet library can properly concatenate print() statements instead of using a single println(), but I'm not familiar enough with the library to know if that works.

A few notes on the code I posted in the previous post:

The F() macro is used for the print() and println() functions to store the literal text in program memory instead of ram.

The PSTR() macro is similar to F(), but is used in some other functions that take text literals, where F() does not work.

strcpy is string copy, where the string is a null-terminated char array stored in ram
strcat is string concatenate, and appends text stored in ram onto the end of an existing string.
strcpy_P and strcat_P are used when the char array is stored in program memory instead of ram.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.