Guardar respuesta comando AT+ en variable

Hola nuevamente, como dice el titulo, quisiera poder guardar la respuesta de un comando AT en una variable para luego poder enviarla por sms..
el tema es así, tengo este código/comando AT "AT+CSQ" que da como respuesta la señal de la sim, así "+CSQ: 14,0". Todo esto es por el serial y que lo veo en el monitor, pero como me explicaban en otro tema, leo tmb y mas importante lo que recibo de la sim, que es donde estaría la info que busco en principio. El problema viene acá, cuando intento aislar ese dato solo, la parte de la señal, juro que intente de mil formas, pero no logro aislar de manera efectiva ese dato. Así es como lo intente:

void Senial() {
  SIM900.print("AT+CSQ");
  //Serial.println("Señal: ");
  Serial.println(mensaje);

supuestamente ahí me muestra lo que busco que es la respuesta del comando AT o sea esto "+CSQ: 14,0" y efectivamente en monitor lo veo. Ahora el problema viene cuando quiero aislarlo
csq
intente con el siguiente código:

void Senial() {
  SIM900.print("AT+CSQ");
  //Serial.println("Señal: ");
  Serial.println(mensaje);
  int senial = mensaje.indexOf(":");
  Serial.println(mensaje.substring(senial, senial - 10));
  Signal = mensaje.substring(senial, senial - 10);
  Serial.println("Esta seria la senial: \0");
  Serial.println(Signal);

y esta es la salida en monitor:
csq rsp

no se como hacer para poder guardar ese mal***o dato en una variable para poder enviarlo x sms...bueno como siempre gracias de antemano y saludos..

Any.

Edito:

hice esto

SIM900.print("AT+CSQ");
char caracter;
String comando;
  while (Serial.available()>0){
    caracter= Serial.read();
    comando.concat(caracter);
    delay(10);
  }  

y muestra un montón de caracteres pero ahora no aparece la respuesta el del comando AT, o sea algo asi: "+CSQ: 14,0":

Honestamente creí, muy equivocada, que sería fácil poder leer el comando, para poder enviarlo x sms..

Edito 2:
intente así:

  SIM900.print("AT+CSQ");
  //Limpia_SMS();
  while (Serial.available()>0)
  {
    SIM900.write(Serial.read());
  }
  String char13 = mensaje;
  uint8_t startPos, endPos;
  startPos = char13.indexOf("+CSQ:") + 2;
  endPos = char13.indexOf("+CSQ:", startPos);
  Sgn = char13.substring(startPos, endPos);
  Serial.println(Sgn);
  Sgn.toCharArray(parametros.Signal, 15);
  salvaSignal();

pero no tampoco lo hace, muestra esto:
nvo_rest
y lo modifiqué así:

  SIM900.print("AT+CSQ");
  //Limpia_SMS();
  while (Serial.available()!= "+CSQ:")
  {
    SIM900.write(Serial.read());
  }
  String char13 = mensaje;
  uint8_t startPos, endPos;
  startPos = char13.indexOf("+CSQ:") + 2;
  endPos = char13.indexOf("+CSQ:", startPos);
  Sgn = char13.substring(startPos, endPos);
  Serial.println(Sgn);
  Sgn.toCharArray(parametros.Signal, 15);
  salvaSignal();

tampoco este directamente no hace nada, que frustante...

Edito 3:

 if (Serial.available()>0)  mensaje=Serial.read();

esto pareciera ser lo mas rápido, lo ejecuta muy rápido al resultado, pero tampoco me sirvió para guardarlo en variable.

Edito 4:
Podría ser porque el dato que busco viene después de que se ejecuta mi código entonces por eso no lo encuentra?

cual

Creo que acá estuviste muy cerca pero luego la erraste

void Senial() {
  SIM900.print("AT+CSQ");
  //Serial.println("Señal: ");
  Serial.println(mensaje);
  int senial = mensaje.indexOf(":");
  Serial.println(mensaje.substring(senial, senial - 10));
  Signal = mensaje.substring(senial, senial - 10);
  Serial.println("Esta seria la senial: \0");
  Serial.println(Signal);

Lo que esta mal es al final el signal - 10

  Signal = mensaje.substring(senial, senial+4);

eso debería darte 14,0
Recuerdo que esos valores corresponden a una tabla per de ahi decides tu.

Dime si te fue de utilidad mi respuesta.

Hola Surbyte gracias por la respuesta, te comento, como vos dijiste "estuviste muy cerca..." jaja si casi.. pero estoy realmente pensando en que lo que ocurre es que el código se esta ejecutando mas rápido que la respuesta del comando, mira la captura, lo que guarda la variable es el código que tira la placa cuando envía el mensaje "+CMGS: 195" :


la variable muestra ": 19" que coinciden con el comando de envió de mensaje que puse antes, porque el de señal esta después, o sea que me parece que es ese el problema..
no sabría como hacer para poder esperar hasta que responda la placa con la señal y ahí buscar con indexof...intente con millis y tampoco, tal vez lo hice mal, delay() no creo que sirva...
como podría hacer para que mi código no guarde en variable hasta que llegue la respuesta de la señal? o que siga leyendo el serial hasta que llegue esa respuesta? (editado)
porque ahí podría hacer esto:

int senial = mensaje.indexOf("+CSQ:");

(cuando es una sola línea de código tmb la tengo que poner con Performed text? )

tmb intente asi:

#define DEBUG(a) Serial.println(a);

   if (Serial.available())
   {
      String data = Serial.readStringUntil('+CSQ:');
      DEBUG(data);
   }

pero tampoco funcionó..

¿No habíamos quedado en que lo correcto es

Serial.available() > 0

? :grin:

No puedes hacer

Serial.readStringUntil('+CSQ:');
      

Porque el delimitador tiene que ser 1 solo caracter y ahí tienes 5.

Hola gatul, si bueno el tema es que mi conocimiento es limitado y para no quedarme cruzada de brazos intento cosas ( así me va jaja) pero bueno es eso, tratar de hacer leyendo, buscando info y probando.. ser inquieta fue mi manera de aprender muchas cosas, el tema es que si algo funciona no quedarme solo con eso sino tratar de entenderlo, asimilarlo ( creo q eso es el proceso de aprendizaje un poco también)..
aunque debo de reconocer que difícil o no esto que consulto, me esta quebrando la cabeza..

edito para gatul:

lo saque de acá:
https://www.luisllamas.es/cadenas-de-texto-puerto-serie-arduino/
explica:

LEER UN CARÁCTER
El primer caso que vamos a ver es leer un único carácter por puerto serie. El código es muy sencillo, ya que únicamente necesitamos leer un byte y convertirlo a char. Pese a ser sencillo puede ser útil, por ejemplo, para aceptar comandos que enviamos a un robot o un vehículo.

#define DEBUG(a) Serial.println(a);
void setup()
{
   Serial.begin(9600);
   Serial.setTimeout(50);
}
void loop()
{
   if (Serial.available())
   {
      char data = Serial.read();
      if ((data >= 'A'  && data <= 'Z') || (data >= 'a' && data <= 'z'))
      {
         DEBUG((char)data);
      }
   }
}

Al carecer prácticamente de procesamiento, la velocidad es la mayor de todos los ejemplos que vamos a ver (del orden de 4-8us). La desventaja es, lógicamente, que sólo estamos recibiendo un único carácter.

Además al ser un proceso manual es sencillo añadir condiciones de validación. En el ejemplo aceptamos caracteres de A a Z en mayúsculas o minúsculas pero sería sencillo, por ejemplo, aceptar únicamente valores de la A a D porque son los cuatro comandos que espera nuestro montaje.

LEER UNA CADENA DE TEXTO CON CLASE STRING
Si queremos leer una cadena de texto completa podemos emplear la clase String, que como sabemos es un wrapper alrededor de un char array incluido en el IDE de Arduino, y que proporciona funciones para trabajar cómodamente con cadenas de texto.

Combinado con la función Serial.readStringUntil(char), podemos leer una cadena de texto recibida por puerto serie de forma cómoda y sencilla. Por ejemplo, es habitual usar como separador '\n', para recibir una línea completa.

#define DEBUG(a) Serial.println(a);
void setup()
{
   Serial.begin(9600);
}
void loop()
{
   if (Serial.available())
   {
      String data = Serial.readStringUntil('\n');
      DEBUG(data);
   }
}

El método es considerablemente eficiente aunque, por supuesto, mucho más lento que recibir un único char. La velocidad depende del procesador y la velocidad de reloj, pero a modo orientativo es del orden de 1ms por caracter recibido.

LEER CADENA DE TEXTO CON CHAR ARRAY
Otra alternativa es emplear un char array en lugar de la clase String para recibir una cadena de texto. El funcionamiento es similar, pero definimos un buffer antes de recibir la cadena, en lugar de una instancia de String.

En esta ocasión empleamos la función Serial.readBytesUntil(char, char*, int), que recibe una cadena de texto por puerto serie y la almacena en el buffer. La función devuelve el número de caracteres recibidos y, por tanto, ocupados en el buffer.

#define DEBUG(a, b) for (int index = 0; index < b; index++) Serial.print(a[index]); Serial.println();
void setup()
{
   Serial.begin(9600);
   Serial.setTimeout(50);
}
void loop()
{
   if (Serial.available())
   {
      char data[20];
      size_t count = Serial.readBytesUntil('\n', data, 20);
      DEBUG(data, count)
   }
}

como te decía antes, mi conocimiento es limitado, trato de aprender, y creí/me pareció que podía funcionar y lo intenté aplicar..

¡Pero a mi me parece perfecto, probando se aprende!
Pero si veo que cometes un error y no te lo digo ¿qué ayuda te estoy dando?

Por otro lado, por si te genera confusión, '\n' aunque para nosotros a primera vista son 2 caracteres, para arduino es 1 solo, es un caracter Nueva línea.

Saludos

Ahora se me ocurrió esto:

  SIM900.print("AT+CSQ");
while(mensaje != "Q")
{
  SIM900.read();
}

no se si esta bien la idea, intenté hacer lo siguiente, primero enviar el comando AT que devuelve el dato que preciso, y que mientras en mensaje no haya una Q siga leyendo y no salga del while..
no se si es correcto la forma de poner en código lo que digo en palabras..

Edito:

no funciona, se queda colgado en el mensaje y no aparece nunca la respuesta de la placa con el valor de la señal, y ya no recibe mas comandos...

nadie tiene una idea de como puedo lograr leer el tan esquivo dato de la señal?

Se puede luego de enviar el comando AT, hacer un bucle hasta que encuentre lo que busco con SIM900.read() o Serial.read()?
donde debería estar haciendo read, el en sim o en el puerto serial?

Tenés que usar

SIM900.read();

porque querés leer lo que se recibe del módulo.
Con

Serial.read();

leés lo que se recibe de la consola.

Podés probar algo así

Enviar comando al módulo
encontrada = false
cadena_entrante = ""
mientras (no encontrada) {
  si hay datos en el buffer del módulo {
    cadena_entrante = leer módulo hasta ('\n')
    si está mi_cadena en cadena_entrante {
      encontrada = true
    }
  }
}
si encontrada {
  truncar cadena_entrante
  guardar datos
}

Ojo que si no encuentra lo que buscas, se queda "encerrado" en el lazo mientras.
Es solo a modo de prueba y una idea general.
Lees cada línea que recibe hasta que encuentra la que tiene los caracteres que buscas.
Después aislas de esa cadena lo que te interesa.

hola gatul gracias por tu respuesta, la verdad que no lo entiendo así con palabras, sin código real no lo imagino...

Es que si lo hago yo no tiene gracia, además todo lo que digo en palabras ya lo has usado en los códigos anteriores. :wink:

Saludos

OK te agradezco igual, y con todo respeto, no busco que me soluciones nada, el código de mi proyecto me costó mucho tiempo y esfuerzo y montón de consultas, lo resolví porque las respuestas (AYUDA) que me dieron fueron concretas, apuntando a parte de la solución o a la solución total de la duda, la cual nunca es todo el proyecto, pero no con evasivas (te digo pero no te digo, como frio y calor)...
yo se que lo voy a resolver pero realmente me incomodó tu comentario "Es que si lo hago yo no tiene gracia..:wink:.."
no veo gracia en nada, al contrario, me parece que en esto o cualquier otra cosa quien esta en verdadera posición de ayudar y tiene esa aparente vocación, no debería tener una actitud tan fría, la verdad me cayó sobradora un ninguneo y casi violenta la respuesta...
no lo tomo como un juego venir a preguntar, tengo el enorme deseo de aprender y resolver mis proyectos como le debe pasar a todos los que se acercan al foro a preguntar, y una sabe que quienes responden lo hacen sin lucro y con muy buena voluntad, por eso siempre agradecida, ojala tuviera la posibilidad por conocimiento de poder ayudar a los que preguntan, pero no es el caso...
te pido disculpas si no te gusta mi descargo pero así me hiciste sentir, esa fue mi impresión..
te repito, muy agradecida igual porque te tomes el trabajo de responder aunque sea lo que me dijiste...
seguiré buscando probando y también preguntando, tal vez consiga resolverlo...saludos
Any.

Ahora si, el molesto soy yo, mirá qué difícil es

SIM900.print("comando");
bool encontrada = false;
String cadena_entrante = "";
while(!encontrada) {
  if(SIM900.available() > 0) {
    cadena_entrante = SIM900.readStringUntil('\n');
    if(cadena_entrante.indexOf("+CSQ:") >= 0) {
      encontrada = true;
    }
  }
}
if(encontrada){
// separar lo que te interesa
}

En la primer línea puse comando porque ya no se cuál es el que querés enviar.
Después usé +CSQ: pero poné el que corresponda.
Encargate vos de separar la subcadena de cadena_entrante que te interesa.

¿Qué era lo tan complicado de pasar de "palabras" a código?

Si lo que tardaste en hacer el "descargo" lo hubieras empleado en leer, tratar de entender y darte cuenta que solo tenías que traducir directamente cada línea de seudocódigo a una línea de código, ya lo tendrías resuelto hace 2 hs, mínimo.

Gracias gatul por tu respuesta de pasar de palabras/seudocodigo a código, pero no funciona.. cuando lee el comando N que es el mensaje que envío para que ejecute el comando at:

int Admin_sg = mensaje.indexOf("#N");

  else  if (Admin_sg >= 0)
  {
    Senial();
  }

void Senial() {
SIM900.print("AT+CSQ");
bool encontrada = false;
String cadena_entrante = "";
while(!encontrada) {
  if(SIM900.available() > 0) {
    cadena_entrante = SIM900.readStringUntil('\n');
    if(cadena_entrante.indexOf("+CSQ:") >= 0) {
      encontrada = true;
    }
  }
}
if(encontrada){
  Serial.println("Encontrada OK \0");
}
}

se queda en mostrar en comando el monitor y se cuelga, ya no recibe mas comandos ni hace nada...

mientras = while

Saludos

Si gatul y yo muy arriba puse esto "Edito 4:
Podría ser porque el dato que busco viene después de que se ejecuta mi código entonces por eso no lo encuentra?..."
si no llega cuando el codigo se esta ejecutando se va a quedar trabado...
mas arriba ya habia recibido de Surbyte la corrección a un error de busqueda dela cadena

Hola Surbyte gracias por la respuesta, te comento, como vos dijiste "estuviste muy cerca..." jaja si casi.. pero estoy realmente pensando en que lo que ocurre es que el código se esta ejecutando mas rápido que la respuesta del comando, mira la captura, lo que guarda la variable es el código que tira la placa cuando envía el mensaje "+CMGS: 195" :

o sea que mi código, con la corrección de Surbyte ya funcionaba en teoría..
el problema a resolver es ejecutar el comando at y poder esperar hasta que se produzca la respuesta y ahí ejecutar mi código para filtrar lo que quiero...mi humilde opinión con mi magro conocimiento, desconozco si hay otra opción mejor y mas precisa...

Se va a quedar en el while hasta que encuentre la cadena, si llega 1 mseg o 1 hora después es lo mismo, el tema es que llegue y que tenga los caracteres que buscas, por eso te aclaré que era a modo de prueba, porque haría falta algo que fuerce la salida del while si pasa, por ej, 1 minuto sin respuesta válida.

Para ver qué está respondiendo el módulo, agregá

Serial.println(cadena_entrante);

debajo de la línea

cadena_entrante = SIM900.readStringUntil('\n');

Lo que muestra el monitor estaria bien


es el envio del comando at, el problema es que pareciera que el while bloquea la respuesta, porque si solo pongo el comando aparece lo mismo que en la imagen y al segundo o 2 la respuesta del nivel de señal...
que podria estar pasando que no permite que la respuesta llegue desde la placa? porque no se si estoy equivocada, pero creería que la placa va a responder al comando...

edito:
o es por esto:

SIM900.readStringUntil('\n');

porque la nueva línea se produce ahí cuando aparece el comando enviado, o sea no haría mas nada a partir de ahí porque ya encontró a '\n'..
entonces ya no leeria mas, se puede poner otra vez

SIM900.readStringUntil(':');

pero esta vez busco los 2 puntos de la respuesta de la señal que es en el único ligar que hay : ?

No tenés ni idea lo que hace el código que te pasé, no?

Después te molestás pero alguien intenta ayudarte y en lugar de hacer lo que te pide hacés lo que se te ocurre.

Ultima oportunidad, agrega la línea que te dije más arriba y mostrame lo que sale en consola, todo lo demás no me sirve.