Figure out if byte* payload contains only numbers

This is one of those questions that I'm out of my element so far that I can't even google it properly.

I'm using the pubsubclient with the typical callback function.

void callback(char* topic, byte* payload, unsigned int length) {

What I would like to figure out is if that payload contains all numbers. How would I go about doing something like this?

A byte can only contain numbers... 0 to 255... Aka, what do you really want to check?

The documentation is not clear to me, upon cursory review, how the payload is being used. Some of the language suggests it contains an array of multiple bytes, so the pointer must point to an array of bytes. Being a message, it is possible that only ASCII is supported, as for 0-127, char and byte are identical... If you really need to know the answer, dive deep into the source code for the library.

I was able to figure it out with a relatively low-tech solution.

void callback(char* topic, byte* payload, unsigned int length) {
  int letter = 0;
  for (int i=0;i<length;i++) {
    if(!isDigit((char)payload[i])){
      letter = letter++;
    }
    Serial.print((char)payload[i]);
  }

  if(letter == 0){
//it's a number, so do your work.  
  }
}

But I'm still stuck with my least favorite topic of dealing with data types. I need to turn that char payload (which I've confirmed is all numbers into an unsigned long, but I'm completely lost.

How do I turn byte* payload into an unsigned long?

How do I turn byte* payload into an unsigned long?

   payload[length] = '\0'; // Add a NULL at the end

   unsigned long value = strtoul((char *)payload, NULL, 10);

mudmin:
How do I turn byte* payload into an unsigned long?

an unsigned long can hold 4 bytes. If you have an array of unsigned long integers, you can:
a) store each byte in the lowest byte of the unsigned long.
b) store 4 bytes in each unsigned long, one in each of the bytes of the unsigned long
c) provide more information as to what the payload is, and what you want it to be in the unsigned long
a) for example, if the payload is an ascii string representing an integer between 0 and 4,294,967,295, you would do the conversion differently than if the payload was an ascii string representing the same value in hexadecimal notation.

mudmin:
I need to turn that char payload (which I've confirmed is all numbers into an unsigned long, but I'm completely lost.

When you refer to "numbers" do you really mean the numeric characters '0' to '9' ?

If you have a cstring containng numeric characters you can convert it to a long with the atol() function (that is ATOL - ascii-to-long)

The parse example in Serial Input Basics illustrates the use of the similar atoi() function.

...R

PaulS:

   payload[length] = '\0'; // Add a NULL at the end

unsigned long value = strtoul((char *)payload, NULL, 10);

PAUL!!!! Thank you. That was exactly what I needed. I'm going to have to do some research on what all that code did, but it worked and did exactly what I needed. Thank you!

Perehama:
an unsigned long can hold 4 bytes. If you have an array of unsigned long integers, you can:
a) store each byte in the lowest byte of the unsigned long.
b) store 4 bytes in each unsigned long, one in each of the bytes of the unsigned long
c) provide more information as to what the payload is, and what you want it to be in the unsigned long
a) for example, if the payload is an ascii string representing an integer between 0 and 4,294,967,295, you would do the conversion differently than if the payload was an ascii string representing the same value in hexadecimal notation.

Thanks so much for the info.

I don't know... But you (or the software) has to know the context.

As septillion says, a byte is a number. Everything in the computer is a binary "number".

A byte might represent an 8-bit integer or part of a 16-bit or 32-bit integer, or part of a floating-point number. It could hold 8-bits that each represent the binary state of something. It could represent an ASCII character. It could be a machine-code instruction or part of a machine code instruction. It could be part of a pixel in an image or part of a WAV sample, or compressed data that has to be decompressed before you can see the picture or hear the audio... etc., etc., etc.

If you open a file in a hex editor it will show the hexadecimal value of all the bytes and wherever there is hex 41 (decimal 65) it will also show an 'A'. The hex editor doesn't know if it's supposed to represent an ASCII 'A', it just knows that it could be an 'A' and any value that can represent an ASCII character will be converted.

Files usually have a header and an extension. Both are helpful to software and your operating system, and the file extension is helpful for you to know the context. If you rename a .WAV file to .TXT you can open it in Notepad and you'll see garbage (it's garbage in the wrong context). But, if you rename a .TXT file to WAV you can't play it in your audio player because there's no WAV header and the software will know something is wrong.

In memory, the software and operating system knows the context from it's address in memory.

Looks like you have the problem solved, so I won't add too much to what has been said... Use parse, in a generic sense, to error check. And pay close attention to "6" and '6' while they may look like the same number 6 to the human mind, they are very different things to the computer. One is a string like the letter A, and the other is a number. To get a character number to become a real number, you have to convert it before you can store it in a variable that accepts numbers.

CodeCruncher:
And pay close attention to "6" and '6' while they may look like the same number 6 to the human mind, they are very different things to the computer. One is a string like the letter A, and the other is a number.

Not quite correct.

The single quotes imply the character '6' which has the Ascii code 54 (decimal). These two lines of code have the same effect

myChar = '6';
myChar = 54;

The double quotes imply a cstring which will contain the characters '6' and '\0'. The \0 is the terminating character.

...R

I thought someone might take me literally. I used the word "like" to imply it was like the letter A (not the actually corresponding Ascii code for 6, I was too tired to look it up the chart, my bad).

The quick and dirty point I was trying to make is pay close attention when dealing with numbers and strings. While your brain knows it's a number, the computer may see it as a string.

CodeCruncher:
I thought someone might take me literally.

The compiler definitely will.

IMHO having the details correct is a lot less confusing for newbies.

...R