[SOLVED] *ETHERNET* Converting char value from client.read() to integer values

Hello everyone!

I have spent the last 8 hours trying to solve this but I just can't. What I am trying to do is convert a simple numeric value that is scraped from the web using "char c = client.read()" to integer and I just can't get it to work. The atoi() function does not like the fact that the variable 'c' has been initiated to client.read(). Any help would be much appreciated. My code:

void loop() {
  // if there's incoming data from the net connection.
  // send it out the serial port.  This is for debugging
  // purposes only:
  
  char c;

  if (client.available()) {
    c = client.read();//////The arduino is grabbing the value from the text file
    Serial.print(c);
    if (c>10){
      digitalWrite(3,1);///If c > scraped value, LED ON
     }
    else
    {
      digitalWrite(3,0);
    }
  }

How can I most efficiently convert "c" to an integer like (56) that it is pulling. The most frustrating thing is that on the Serial Monitor, the value shown is exactly "56" but my logic for LED does not work. Again, any help appreciated.

PS: I have tried to search through the forums and didn't find help. I have seen a lot of folks get irritated at questions about how to use atoi() but I couldn't find a defacto example using client.read() and all other example are vague at best.

Can you post a complete sketch? If you don't, you waste time while people ask you to do that. Please post a minimal sketch that demonstrates the problem, as opposed to hundreds of lines of code.

Sure...sorry. I didn't want to post the entire sketch (code) just for the reason that it may be too long and nobody wants to see too much code :(.

Below is the full code. (adaptation of an official arduino ethernet code).

My question basically is how do I convert the string/char that I pulled from a PHP file (which only puts out numbers like 51,52, 108 etc) to integers in arduino on which I can do some comparison on. That is, if the PHP returned "75", I would like to put the code in my aruduino "If PulledData> 70, Turn LED ON" etc.

Much thanks!

/*
  Repeating Web client
 
 This sketch connects to a a web server and makes a request
 using a Wiznet Ethernet shield. You can use the Arduino Ethernet shield, or
 the Adafruit Ethernet shield, either one will work, as long as it's got
 a Wiznet Ethernet module on board.
 
 This example uses DNS, by assigning the Ethernet client with a MAC address,
 IP address, and DNS address.
 
 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 
 created 19 Apr 2012
 by Tom Igoe
 
 http://arduino.cc/en/Tutorial/WebClientRepeating
 This code is in the public domain.
 
 */

#include <SPI.h>
#include <stdlib.h>
#include <Ethernet.h>

// assign a MAC address for the ethernet controller.
// fill in your address here:
byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
// fill in an available IP address on your network here,
// for manual configuration:
IPAddress ip(192,168,1,103);//FAROOQ comment-->Give it a NEW UNUSED IP

// fill in your Domain Name Server address here:
//IPAddress myDns(8,8,8,8);

// initialize the library instance:
EthernetClient client;

char server[] = "192.168.1.105";//FAROOQ comment-->This is your server address where you are hosting the LED website files

unsigned long lastConnectionTime = 0;          // last time you connected to the server, in milliseconds
boolean lastConnected = false;                 // state of the connection last time through the main loop
const unsigned long postingInterval = 1000;  // delay between updates, in milliseconds

void setup() {
  // start serial port:
  Serial.begin(9600);
  pinMode(3, OUTPUT);//////////////////////////////FAROOQ COMMENT--> Sets Pin3 as OUTPUT pin
  // give the ethernet module time to boot up:
  delay(1000);
  // start the Ethernet connection using a fixed IP address and DNS server:
  Ethernet.begin(mac, ip);
  // print the Ethernet board/shield's IP address:
  Serial.print("My IP address: ");
  Serial.println(Ethernet.localIP());
}

void loop() {
  // if there's incoming data from the net connection.
  // send it out the serial port.  This is for debugging
  // purposes only:
  
  char c;

  if (client.available()) {
    c = client.read();//////The arduino is grabbing the value from the text file
    Serial.print(c);
    if (c>10){
      digitalWrite(3,1);///If c > scraped value, LED ON
     }
    else
    {
      digitalWrite(3,0);
    }
    
  
  }

  // if there's no net connection, but there was one last time
  // through the loop, then stop the client:
  if (!client.connected() && lastConnected) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
  }

  // if you're not connected, and ten seconds have passed since
  // your last connection, then connect again and send data:
  if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) {
    httpRequest();
  }
  // store the state of the connection for next time through
  // the loop:
  lastConnected = client.connected();
}

// this method makes a HTTP connection to the server:
void httpRequest() {
  // if there's a successful connection:
  if (client.connect(server, 80)) {
    Serial.println("connecting...");
    // send the HTTP PUT request:
    client.println("GET /CAISO_LMP.php");///////Grab the text file
    //client.println("GET /CAISO_LMP.txt");///////Grab the text file
    client.println("Host: www.arduino.cc");
    client.println("User-Agent: arduino-ethernet");
    client.println("Connection: close");
    client.println();

    // note the time that the connection was made:
    lastConnectionTime = millis();
  } 
  else {
    // if you couldn't make a connection:
    Serial.println("connection failed");
    Serial.println("disconnecting.");
    client.stop();
  }
}

mfarooqalikhan:
I have spent the last 8 hours trying to solve this but I just can't. What I am trying to do is convert a simple numeric value that is scraped from the web using "char c = client.read()" to integer and I just can't get it to work. The atoi() function does not like the fact that the variable 'c' has been initiated to client.read(). Any help would be much appreciated. My code:

You need to be specific as to what you want. atoi() takes a string (a char array). But later, you say...

How can I most efficiently convert "c" to an integer like (56) that it is pulling. The most frustrating thing is that on the Serial Monitor, the value shown is exactly "56" but my logic for LED does not work. Again, any help appreciated.

So, as an ASCII character, it is an '8', which is 56 in decimal. If you want it to be an integer of value 8, you could subtract '0' (or 0x30, or 48 decimal) from it.

If you want it to be 56, well, it already is 56, as you saw when you did a Serial.print.

Have a look at this:

void setup() {
    Serial.begin(115200);
    char foo = 56; // (0x38 hex, or 56 decimal)
    int bar = foo;
    
    Serial.println (foo);
    Serial.println(bar);
    
    if (foo > 10) {
      Serial.println("Yes!");
     }
    else
    {
      Serial.println("No!");
    }
        if ( bar > 10){
      Serial.println("Yes!");
     }
    else
    {
      Serial.println("No!");
    }
    while (1) {}
}

void loop() {
  }

Thanks lar3ry for responding. It seems to me I have not been very clear in stating my problem.
So I am going to break down my problem.

  1. I have a php file (web browser script) that when ran outputs integers.
    So if I were to type in c:\xampp\test.php in my browser, it gives me integers. My example was "56". Its basically a price value for a commodity.
  2. I want my ARDUINO to grab that value as an INTEGER.
    The thing with ARDUINO is that it very easily grabs that value (and I can see that on my monitor) but when doing logical comparison it fails. For example, if my php generated "56". I stored that "56" on to a variable called "c" (initiated as a char). If I print c onto the serial monitor, I see "56". But if I do a logical compare like (is c<100? And it says NO). Clearly it is! So, even though I can see my serial monitor displaying "56" arduino is uing the ASCII equivalence.
  3. Hence, my question is HOW do I convert the c= client.Read() to an integer value that I can use logical comparison on?

Hope this makes sense! Thanks again.

Are you getting these values as text, or as binary integers? Your code has comments that suggest it's text. If that's so, you're not getting 56, you're getting "56". The first is a numerical value, corresponding to 56 decimal, 38 hexadecimal, and 00111000 binary. The second is a two-byte string, and the values of those bytes are 53 and 54 decimal.

Investigate. Change this:

    c = client.read();
    Serial.print(c);

to this:

    c = client.read();
    Serial.print(c);
    Serial.print(" ");
    Serial.println(c,DEC);

That'll print each character on its own line, along with its decimal representation. I suspect that you'll find that you're receiving more than one character, and that those characters represent the number that you're looking for.

atoi() expects a pointer to a character array. It skips any initial whitespace, and then looks for characters in the range '0' ... '9'. It takes as many as it finds in a row, and interprets those characters as a numerical value. If you pass it a character, the compiler complains and gives up, because it can't turn a character into a pointer to a character array. If you pass it the address of the character, it'll compile, but it will keep looking at characters, and keep converting, until it finds a non-decimal character, or a string-ending zero. I don't think that's what you want.

I think you'll have to collect the characters into a character array, maybe add a string-terminating zero, and then give the array's pointer to atoi(), in order to get the results you hope for.

[Edit: Fix grammar]

it gives me integers. My example was "56". Its basically a price value for a commodity.

You may need to drop back and adjust your thinking. In the above quote, 56 is a two byte character representation of a number. The arduino just reads one byte at a time. You will probably need to capture a String or c-string of the incoming byte stream and then evaluate that for the two byte character string 56 or other value, then convert the captured bytes/characters into the integer represented by the bytes/characters.

Thanks tmd3 and zoomkat!

I clearly see what you guys are saying. I basically need to capture the string that I am getting and convert each one to an integer.

tmd3, I tried using
Serial.print(c);
Serial.print(" ");

and I can see on my serial monitor
4 9
(there is a space in between 4 and 9 as expected from the Serial.print(" ")). The PHP result is the integer 49.
NOW that I have that down. I basically need to capture each of those strings and convert them to an integer.

My question is how do I capture one at a time? That is capture "4" first, convert to integer, and then capture "9" and convert to integer.
Thanks for the responses guys. I will surely document this well and post at the ends of the this thread so folks in the future can get it quickly.

There are basically two ways to do it. You can do it one character at a time, converted and placed into an int, or you can gather chartacters into a char array and use atoi().

I am going to assume that client.read() returns a single char.
I'm also going to assume the input ends with a newline character. You can use fixed length, end of input character, or a delimiter before the next set of characters.

   char c[5];  // assume a maximum of 4 digits plus a NULL terminator
   int n;
   byte indx = 0;

   if client.available() {
      c [ indx ] = client.read();
      c [ indx+1 ] = 0;
      indx ++;
      if (c == '\n') {
         n = atoi(c);
         goDoSomethingWith(n);
         }
      }

// or..

   char c;
   int n;

   if client.available() {
      c  = client.read();
      n = (n * 10) + (c - '0');
      if (c == '\n') {
         goDoSomethingWith(n);
         }
      }

The below is servo code, but it demonstrates capturing a String representing a number, then converting the String into an integer. If the data stream from the server is large, you might use something like the below textfinder to help.

http://playground.arduino.cc/Code/TextFinder

// zoomkat 7-30-10 serial servo test
// type servo position 0 to 180 in serial monitor
// for writeMicroseconds, use a value like 1500
// http://arduino.cc/en/uploads/Tutorial/String.zip for WString.h

#include <WString.h> //provides easy string handling
String readString = String(100);
#include <Servo.h> 
Servo myservo;  // create servo object to control a servo 

void setup() {
	Serial.begin(9600);
        myservo.attach(9);
        }

void loop() {

        while (Serial.available()) {
        delay(10);  
    	if (Serial.available() >0) {
        char c = Serial.read();  //gets one byte from serial buffer
        readString.append(c); } //makes the string readString
        }
        
      if (readString.length() >0) {
      Serial.println(readString);
      int n;
      n = atoi(readString); //convert string to number
      myservo.writeMicroseconds(n);
      //myservo.write(n);
      readString="";
      } 
   }

lar3ry...
Unofrtunately it didn't work. Very promising but it still wont recognize the integer as "56". It still thinks 56<30.

So I tried this:

char c[5];
int n;
byte indx = 0;

if (client.available()) {
c [ indx ] = client.read();
c [ indx+1 ] = 0;
indx ++;

n = atoi(c);
Serial.print(n); ---> Here I get perfect 56 and seemingly it has no problem identifying it as int
if (n<30){
digitalWrite(3,1); --> Here as n is NOT greater than 56, the LED should not go on BUT IT DOES! :frowning:

One thing to note is that your command of "/n" doesn't work as it NEVER sees that if condition as TRUE.
Plus, after I have done n =atoi(c);
I did
n = n+100; -->thinking it would retrn 100+56=156, but it doesn't. Its 105106. WTF is it doing?

Any comments kind folks? THANKS!
PS: I even tried your other method of n = (n * 10) + (c - '0'); SAME ISSUE.

char c[5]; 
   int n;
   byte indx = 0;

These must be global. If they are in loop(), they will be reinitialized every time through loop()

   if (client.available()) {
      c [ indx ] = client.read();
      c [ indx+1 ] = 0;
      indx ++;
      
         n = atoi(c);

Where is your if() that acts as the end of gathering characters for the string?

         Serial.print(n); ---> Here I get perfect 56 and seemingly it has no problem identifying it as int
         if (n<30){
         digitalWrite(3,1); --> Here as n is NOT greater than 56, the LED should not go on BUT IT DOES! :(

The first time through, n will = 5, because you have not put in the if() that determines all characters are collected.

One thing to note is that your command of "/n" doesn't work as it NEVER sees that if condition as TRUE.

It isn't "/n". It is '\n'

"/n" is a string that contains a /, an n and a NULL terminator.
'\n' is a single character that is a newline.

As well, it only makes sense to use that if your input from client.read end with a newline. Did you read the part about delimiting or counting characters?

Plus, after I have done n =atoi(c);
I did 
n = n+100; -->thinking it would retrn 100+56=156, but it doesn't. Its 105106. WTF is it doing?

No idea whatsoever. I can't see the code you tired.

PS: I even tried your other method of n = (n * 10) + (c - '0'); SAME ISSUE.

Same issue as what?

The code I gave will work fine, provided the assumtions I mentioned are true. If they aren't and if you put the initialization of the variable within loop(), it will not work.

You can't just throw stuff into your sketch without thinking about what it will do in the place you put it. You have to read and understand the logic of the code, and adapt it to your situation.

Have a look at Nick Gammon's Serial Tutorial at Gammon Forum : Electronics : Microprocessors : How to process incoming serial data without blocking
Read and understand, then adapt it.

You have a lot of good suggestions already. I'll add one:

Write a program that collects characters from the serial monitor, identifies the terminating character, does atoi() on the result, and prints the resulting integer. When you get that working, transfer the method to your web-based program.

Here's what I like about that method:

  • The code will be short. You can post the whole sketch each time, and we won't have to work with snippets, or wonder if you made some other change in the program that isn't shown.
  • There won't be all that distracting other stuff.
  • You'll be in control of the input. You'll know what you put in, and you'll see what you get out. You, and we, won't have to speculate about what some server is sending you.

[Edit: Added omitted word, "you."]

Write a program that collects characters from the serial monitor, identifies the terminating character, does atoi() on the result, and prints the resulting integer.

I'll even give you a head start:

#define SOP '<'
#define EOP '>'

bool started = false;
bool ended = false;

char inData[80];
byte index;

void setup()
{
   Serial.begin(57600);
   // Other stuff...
}

void loop()
{
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 79)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }

  // We are here either because all pending serial
  // data has been read OR because an end of
  // packet marker arrived. Which is it?
  if(started && ended)
  {
    // The end of packet marker arrived. Process the packet

    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
}

Where it says "Process the packet" is where you call atoi() to convert inData to an int.

The start and end markers are '<' and '>', so sending "<456>" will result in atoi() returning the value 456.

Guys!

Thanks again for everyone's response. I took heed from everyone and too multiple steps back to first study Nick Gammon's serial tutorial. I studied it and got the full idea.

The MAIN difference that I see with the ethernet is that TERMINATING character. Nick Gammon's example works because he is expecting the terminator to be "\n". Now, with ETHERNET I have no idea what that is?

So, how do I know what the terminating character is? Does it end with new line i.e. '\n'? Any tips?

Again, thanks to everyone. as mentioned before, if my code works, I will post that as an example for anyone else to use.
THANKS!

Ok guys I solved it! What I did was I just appended a special character at the end of my data stream from the PHP.

My PHP code now has this:
echo $prices[0].'>';// This appends the special character ">" to the data I am trying to scrape.

Additionally, I just modified Nick Gammon's code (which was written for Serial and converted it to Ethernet). So for all those who want to know how it is done, the code is below.

Thanks to EVERYONE who has helped me. I got my arduino just last week and have really pushed myself to not only learn arduino's programming language but also PHP and HTML. I am getting there :).

/*
Example of processing incoming serial data without blocking.
 
 Author:   Nick Gammon
 Modified for ETHERNET by Farooq Ali Khan
 Date:     13 November 2011. 
 Modified: 31 August 2013.
 Ethernet Mod: 1/27/2014.
 
 Released for public use.
 */

///////////////////////////////////////////////Ethernet Stuff 1
#include <SPI.h>
#include <Ethernet.h>
byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};//MAC ADDRESS
IPAddress ip(192,168,1,103);//Provide Unused IP Address
// initialize the library instance:
EthernetClient client;

char server[] = "192.168.1.105";//Provide server to scrape data from

unsigned long lastConnectionTime = 0;          // last time you connected to the server, in milliseconds
boolean lastConnected = false;                 // state of the connection last time through the main loop
const unsigned long postingInterval = 1000;  // delay between updates, in milliseconds
///////////////////////////////////////////////

// how much serial data we expect before a newline
const unsigned int MAX_INPUT = 50;

void setup ()
{
  Serial.begin (9600);
  delay(1000);
  ///////////////////////////////////////////////ETHERNET STUFF 2
  Ethernet.begin(mac, ip);
  Serial.print("My IP address: ");
  Serial.println(Ethernet.localIP());
  ///////////////////////////////////////////////
} // end of setup

// here to process incoming serial data after a terminator received
void process_data (const char * data)
{
  // for now just display it
  // (but you could compare it to some value, convert to an integer, etc.)
  //Serial.println (data);
  int n = atoi(data);//Convert scraped ethernet data to INTEGER...YES!!!!!!!!
  //n = n+100;
  Serial.println(n);/////Will display the converted data to serial monitor
  
}  // end of process_data

void processIncomingByte (const byte inByte)

{
  static char input_line [MAX_INPUT];
  static unsigned int input_pos = 0;

  switch (inByte)
  {

  case '>':   ///////PAY ATTENTION! For my case, my TERMINATING character from the ETHERNET data stream was ">". THIS IS ////////IMPORTANT. Check what your terminating character is!
    input_line [input_pos] = 0;  // terminating null byte

    // terminator reached! process input_line here ...
    process_data (input_line);

    // reset buffer for next time
    input_pos = 0;  
    break;

  case '\r':   // discard carriage return
    break;

  default:
    // keep adding if not full ... allow for terminating null byte
    if (input_pos < (MAX_INPUT - 1))
      input_line [input_pos++] = inByte;
    break;

  }  // end of switch

} // end of processIncomingByte  
char c;
void loop()
{
  // if serial data available, process it
  //if (Serial.available () > 0)
  //processIncomingByte (Serial.read ());
  ///////////////////////////////////////////////ETHERNET STUFF 3...Instead of serial, we will use client.read() for ethernet
  if (client.available()) {
    c = client.read();
    processIncomingByte (c);
    
    //digitalWrite(3,1);
    //Serial.print(c);
    //Ethernet Stuff
    // if there's no net connection, but there was one last time
    // through the loop, then stop the client:
    if (!client.connected() && lastConnected) {
      Serial.println();
      Serial.println("disconnecting.");
      client.stop();

    }
  }

    // if you're not connected, and ten seconds have passed since
    // your last connection, then connect again and send data:
    if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) {
      httpRequest();
    }
    // store the state of the connection for next time through
    // the loop:
    lastConnected = client.connected();


  
    // do other stuff here like testing digital input (button presses) ...

}  // end of loop

  // this method makes a HTTP connection to the server:
  void httpRequest() {
    // if there's a successful connection:
    if (client.connect(server, 80)) {
      Serial.println("connecting...");
      // send the HTTP PUT request:
      client.println("GET /yourwebpage.html");///////The  "[b]SERVER_IP/yourwebpage.html[/b]" is the page address you want to ///scrape
      
      client.println("Host: www.arduino.cc");
      client.println("User-Agent: arduino-ethernet");
      client.println("Connection: close");
      client.println();

      // note the time that the connection was made:
      lastConnectionTime = millis();
    } 
    else {
      // if you couldn't make a connection:
      Serial.println("connection failed");
      Serial.println("disconnecting.");
      client.stop();
    }
  }
/////////////////////////////////////////////// This should work now!

So, how do I know what the terminating character is? Does it end with new line i.e. '\n'? Any tips?

Print each character received twice - once as a character and once as an int, in HEX format. You'll quickly see what the numeric value for each character is, and see that each line of the server response ends with a carriage return and a line feed. The end of the response from the server is the sequence (that is an empty line).