indexOf with range

Hello,

I request every 10 seconds signal quality and response have string "+CSQ: 21,99"

Response have range, i need only first value before comma:

  1. +CSQ: (20 - 30) - Excellent
  2. +CSQ: (15 - 19) - Good
  3. +CSQ: (10 - 14) - Normal
  4. +CSQ: (2 - 9) - Marginal

My simple code work, but i need 4 conditions for every type of signal, how i can add range in like response.indexOf("+CSQ: 20" || "+CSQ: 21" ) - it not working .

if(response.indexOf("+CSQ: 20") > 0) {
Serial.println("Excellent");
}

Search the string for the text "+CSQ:" and extract the number just after it, convert to integer and than compare it with your thresholds numerically.

If you insist on using Strings

String response = "+CSQ: 21,99";

void setup()
{
    Serial.begin(115200);
    int valueInt = response.substring(response.indexOf(":") + 2, response.indexOf(",")).toInt();
    Serial.println(valueInt);
}

void loop()
{
}

You can use the value of valueInt to test the range of the value

2 Likes

I suggest to use the C-string library to parse the C-string, and obtain the numeric result, as follows:

// test strtok() behaviour

char delim[] = ":";  //substring delimiters

void setup() {

  char* pch;  //string pointer

  char message[] = "+CSQ: 20";

  Serial.begin(115200);
  while (!Serial); //wait for connection
  
 // get first token
  pch = strtok(message, delim);
  Serial.print("strtok returns ");
  Serial.println(pch);
  
  //get second token
  pch = strtok(NULL, delim);
  Serial.print("strtok returns ");
  Serial.println(pch);
  
  // parse it to an integer
  int val = atoi(pch);
  Serial.print("value = ");
  Serial.println(val);

if (val >= 20) Serial.println("Excellent");

}

void loop() {}
2 Likes

Exactly what I need, thank you very much :slight_smile:

The only thing is that it leads all the data in the request to this form, but how can I make it look only at a specific line starting with "+CSQ:"

Since I have several such variables to process, so that it does not touch the rest of the data.

Some study of the C-string library page linked in post #4 should help to learn how powerful it is, and why it easy to solve such problems.

Change this

 // get first token
  pch = strtok(message, delim);
  Serial.print("strtok returns ");
  Serial.println(pch);

to something along this line:

 // get first token
  pch = strtok(message, delim);
  if (strncmp(pch,"+CSQ",4) == 0) {  //found desired message
 // get second token, parse value and print result
 }
1 Like

If i change code he not give any value.
Response have this data:

14:14:26.894 -> AT+HTTPTERM
14:14:26.894 -> OK
14:14:37.874 -> +HTTPACTION: 2,200,710
14:14:37.874 -> +CNSMOD: 0,8
14:14:37.874 -> OK
14:14:37.874 -> LTE
14:14:54.040 -> AT+CSQ
14:14:54.040 -> +CSQ: 18,99

After when i try check

if(response.indexOf("+HTTPACTION: 2,200") > 0) {

he return val = 2 because it after checking signal quality. response for CSQ i make every 10 seconds, response from +HTTPACTION: 2,200 - every 20 seconds.

void checksimsignal() {
delay(10000);
SIM7670Serial.print("AT+CNSMOD?\r\n");
String response = SIM7670Serial.readString();
Serial.println(response);
char* pch;  //string pointer
char message[20];
response.toCharArray(message, 20);
  pch = strtok(message, delim);
   if (strncmp(pch,"+CSQ",4) == 0) {
  pch = strtok(NULL, delim);  
  // parse it to an integer
  int val = atoi(pch);
  Serial.println(val);
}

Not show any data.

Next code to check https status

void ltehttpshead() {
delay(15000);
SIM7670Serial.print("AT+HTTPACTION=2\r\n");
String response = SIM7670Serial.readString();
   Serial.println(response);
  if(response.indexOf("+HTTPACTION: 2,200") > 0) {
      // Call connected
      Serial.println("Its worked");
}

if i change string to if (strncmp(pch,"+CSQ",4) != 0) {

he show val = 2

I want to check +CSQ and +HTTPACTION: 2,200 and other like gps\gnss. I try to change response sting to another, but how i think all data spins in SIM7670Serial.readString(); and i need somehow separate them by name, otherwise it parses all the lines.

Post ALL the revised code, so we can see where the mistake is.

I try to check what have pch with code

pch = strtok(message, delim);
  Serial.println("---");
  Serial.println("pch:");
  Serial.print(pch);
  Serial.println("---");

And he show this, he not catch this stirng, but it have in request:

16:56:16.952 -> AT+CNSMOD?
16:56:16.952 -> +CNSMOD: 0,8
16:56:16.952 ->
16:56:16.952 -> OK
16:56:16.952 ->
16:56:16.952 -> ---
16:56:16.952 -> pch:
16:56:16.952 ->
16:56:16.952 -> +HTTPACTION---
16:56:16.952 -> LTE
16:56:33.139 -> AT+CSQ
16:56:33.139 -> +CSQ: 19,99
16:56:33.139 ->

May be i not right convert string to char

String response = SIM7670Serial.readString();
char* pch; //string pointer
char message[20];
response.toCharArray(message, 20);

Full code, i delete part code what related with display.

#include <SoftwareSerial.h>
SoftwareSerial SIM7670Serial(2, 3); // RX, TX

char delim[] = ":";  //substring delimiters

void setup() {

  Serial.begin(115200,SERIAL_8N1);
  SIM7670Serial.begin(115200,SERIAL_8N1);
  sendATCommand("AT+CGMM", "OK", 1000); // check communication
  sendATCommand("AT+CMGF=1", "OK", 1000); // set SMS format to text
}

void checksimsignal() {
delay(10000);
SIM7670Serial.print("AT+CNSMOD?\r\n");
String response = SIM7670Serial.readString();
Serial.println(response);
char* pch;  //string pointer
char message[100];
response.toCharArray(message, 100);

  pch = strtok(message, delim);
  Serial.println("---");
  Serial.println("pch:");
  Serial.print(pch);
  Serial.println("---");
   if (strncmp(pch,"+CSQ",4) == 0) {
  pch = strtok(NULL, delim);  
  // parse it to an integer
  int val = atoi(pch);
  Serial.print("val:");
  Serial.println(val);
}

void ltehttpshead() {
delay(15000);
SIM7670Serial.print("AT+HTTPINIT\r\n");
SIM7670Serial.print("AT+HTTPPARA=\"URL\",\"https://domain.tld\"\r\n");
SIM7670Serial.print("AT+HTTPACTION=2\r\n");
SIM7670Serial.print("AT+HTTPTERM\r\n");

String response = SIM7670Serial.readString();
   Serial.println(response);
  if(response.indexOf("+HTTPACTION: 2,200") > 0) {
      Serial.println("Its worked");
    }
} 

void loop() {
  display();
  checksimsignal();
//  ltehttpshead();
}

If i turn off ltehttpshead(); he show this in response

17:35:29.504 -> ---
17:35:29.504 -> pch:
17:35:29.504 -> AT+CSQ
17:35:29.504 -> +CSQ---

If i turn on ltehttpshead(); he show this

17:37:27.075 -> ---
17:37:27.075 -> pch:
17:37:27.075 ->
17:37:27.075 -> +HTTPACTION---

If active checksimsignal(); in loop not working string if(response.indexOf("+HTTPACTION: 2,200") > 0) {
in ltehttpshead();

I found reason, if i make all requests in one void and response, all parsing ok. Many thanks for the help.

And yet I still need your help.

I found a similar example where I want to catch a specific store by name and I can’t. First I want to parse and get the value from test1 and then the value from test2

Help me get this using my example, since it only parses the first one, but I need it by name, but it doesn’t find it by name. In order not to bother with my code, it will be very clear and then I will adapt it into my own.

Similar to this example, my query also has some unnecessary data, but it is not looking for some reason. Although everyone starts on a new line.

I want get val1 and val2 from test1 and test2.

// strtok example - parse tokens

void setup() {
  // put your setup code here, to run once:
    Serial.begin(115200);
    char str[] ="RL3]\[Test1 1a}|{3}|{S]\[Test2 2b}|{41}|{L]\[Test 3}|{1234}|{L";    // text to tokenise
    char * pch;                     // pointer to tokens
    Serial.print("Splitting string ");
    Serial.print(str);
    Serial.println(" into tokens:");
    pch = strtok (str,"}]\[|{");         // get first token
    while (pch != NULL)
      {
      int x=999;
      Serial.print("string found ");
      Serial.println(pch);          // print it
      pch = strtok (NULL, "}]\[|{");     // get next token
     }  
}

void loop() {
  delay(4000);
Serial.begin(115200);
    char str[] ="RL3]\[Test1 1a}|{3}|{S]\[Test2 2b}|{41}|{L]\[Test 3}|{1234}|{L";    // text to tokenise
    char * pch;                     // pointer to tokens
    Serial.print("Splitting string ");
    Serial.print(str);
    Serial.println(" into tokens:");
    pch = strtok (str,"}]\[|{");         // get first token
    if (strncmp(pch,"Test1",5) == 0) {
      Serial.print("i found test1 string");
      pch = strtok(NULL, " ");
      Serial.print(pch);
    }
    while (pch != NULL)
      {
      int x=999;
      Serial.print("string found ");
      Serial.println(pch);          // print it
      pch = strtok (NULL, "}]\[|{");     // get next token
     }  


}

Thank you in advance, I should have done this right away.

Tokens equal to test1 and test2 are not in the example string.

There are a couple of similar tokens in the example string, like "Test1 1a", "Test2 2b" and "Test 3", but string length, blanks and character case all matter when making comparisons.

Since the example string uses some undefined syntax and the given example seems not to be representative of the general problem, there is no point in writing code to parse it.

You helped me a lot, I am very grateful to you, I think I found a way to get the second value data type using this example:

String string = "It was hot (so hot!) I'm telling you.";
int left = string.indexOf("(");
int right = string.indexOf(")");

// pull out the text inside the parens
String sub = string.substring(left+1, right); // sub is "so hot!"