Problemas, sin lógica, entre Arduino Nano y SIM900

Hola lap2021: con respecto a no leer los SMS
Es posible, y repito, es posible que cuando estés en el delay(25000), el SIM900 le esté mandando los datos al arduino y este los pierda. Piensa que el buffer de recepción que estas usando es vía software. Yo tuve bastantes problemas al principio con los SIM900 y el SoftwareSerial por perdida y truncamiento de datos.
Podrías evitar ese delay usando millis, que para tu caso sería bastante simple
Prueba esto: (no esta probado)

// declara global
unsigned long Alert=0;

// en el loop
if(Alert) activate_ALERT("0");
void activate_ALERT(String zona){
 if(Alert==0){
  	monitoring = OFF;
	sendSMS(zona);
	digitalWrite(releR1, LOW);
	Alert=millis();
	return;
	}
 if(millis()-Alert>25000) {  //  delay(25000);
	digitalWrite(releR1, HIGH);
	Alert=0;
	}
}
Como te indico es una idea a depurar y/o mejorar
Saludos

Una recomendación @lap2021 y debo felicitarte por no repetir cada respuesta, pero por favor copia y pega lo que alguien te dice usando la cita o quote.
De este modo, mira como te respondo.

  1. Que tienen los pines A0 y A1 que no chupan ruido del mismo mosmo que lo hacen los demás pines Analógicos? porque en esos dos deje la zona 1 y sin problemas con ellos. Esto mucho no me importa porque ya no es problema.

Los pines A0 y A1 mas alla de lo que cita @gatul no tienen nada extra, y puedo imaginar que el problema de ruido se debe a que simplemente no tienes una R de 10K del PIR a masa.
Entonces cuando lees con el ADC, el capacitor del Sample & Hold queda cargado y al cambiar el multiplexor tomas valores raros.

Por eso no es bueno su uso como medidor de valores digitales.

Verifica lo que digo agregando una R de 10K a GND y luego nos dices si hay ruidos o no?

Ahora te planteo algo y perdon porque sumarme tarde a tu proyecto.
Existen librerías que hacen las cosas mucho mejor que uno en líneas generales.
Esta es vieja 7 años pero mira lo que hace

GSM SHIELD Library

Para la próxima considera usar una y de nuevo no porque lo tuyo este mal, sino porque esta que te propongo es mas eficiente, al menos en lo que yo te menciono que es el hecho de esperar a que el SIM responda, puede sin embargo introducir mas Kbytes pero tu código no es grande como para preocuparse por ello.

Buenas, les cuento que logré solucionar algunos problema pero no todos por descgracias!.

gatul

Revisa el manejo de la variable **monitoring **porque solo switch_On() la pone ON pero switch_Off() no lo hace y monitoring está OFF desde activate_Alert() por eso despues de leer el msj salta al else.

PD: lo de A0 y A1 podría ser porque tienen una configuración levemente diferente porque se usan para un comparador interno.

El manejo de la monitoring está así a propósito justamente para que rearme sola luego de un alert. Con respecto a A0 y 1 gracias por la info!.

bosoft

Podrías evitar ese delay usando millis, que para tu caso sería bastante simple

No logré hacer que funcione, cuando puse eel millis me volvió el problema de alarmarse la zona 2 aún estando conectado a los pines digitales.

surbyte

Para la próxima considera usar una y de nuevo no porque lo tuyo este mal, sino porque esta que te propongo es mas eficiente, al menos en lo que yo te menciono que es el hecho de esperar a que el SIM responda, puede sin embargo introducir mas Kbytes pero tu código no es grande como para preocuparse por ello.

Esto es una de las cosas que me falta ponerle, dado que a verces pasa que la SIM se sale de linea por falta de antena y luego no se vuelve a registrar con lo cual queda la alarma aislada a nivel comunicaciones. Intente hacerlo pero sin éxito el tema de esperar un ok y controlar status y hacer que se reinicie en caso de salirse de linea.

Bueno, les cuento que el problema que sigo teniendo es justamente mientras que está sonando por una alarma debo esperar a que termine de sonar (termine el delay) para así mandarle mensaje de Off y lo tome y lo procese.

Debajo colocaré nuevo código...

Gracias!!

Ya te habrán dicho todo lo que hagas con delay() detiene la ejecución del flujo del programa.
Lee en documentación máquina de estados y millis().

Deja este proyecto, entiende como usar una máquina de estados y millis() y luego cuando lo entiendas vuelve. No lo hagas simultáneamente porque solo te vas a complicar.
Pero te aseguro que es la respuesta a tu problema.
De todos modos tone() no se lleva bien con casi nada porque en el procedimiento debes indicarle cuanto tiempo debe hacer dicho tono y eso de nuevo es bloqueante o sea usa delay().

Busca la forma de que todo lo que involucre tonos sea de tal manera que no te DETENGA al arduino.

lap2021:
El manejo de la monitoring está así a propósito justamente para que rearme sola luego de un alert.

Pues así como está da como resultado lo dijiste que era tu problema.
Te recuerdo lo que decías

lap2021:
Ahora, si mientras esta sonando yo envío mensaje de que se apague debería: esperar a que termine el delay, se apague la sirena y lea mensajes por ser la primera acción o linea de código del loop... pero no lo hace!!; una vez que termina y vuelve al loop es como que pasa por alto la lectura de mensajes y entra al "else" donde invoca a la función alertTimeOnCheck() y se rearma la alarma de forma automática (esto es porque si no recibe mensaje alguno se rearma sola para volver a monitorear sensores).

Saludos

#include <SoftwareSerial.h>
#include <Arduino.h>

/*** PARÁMETROS ***/
/******************************/
#define BUZZER 5
#define releR1 2
#define bluePin 4
#define SERIAL_BAUDRATE 9600
#define GSM_BAUDRATE 9600
#define RX_pin 10
#define TX_pin 11
#define ON 1
#define OFF 0
#define sensorPirP1 A0
#define sensorEcoP1 A1
#define sensorPirP2 6
#define sensorEcoP2 7
/******************************/

bool state, monitoring;
int lecturaPirP1, lecturaEcoP1, lecturaPirP2, lecturaEcoP2;
SoftwareSerial *SIM900;
String incomingSMS, msessage;
 
void setup(){
  state = OFF;
  monitoring = OFF;
  SIM900 = new SoftwareSerial(RX_pin, TX_pin);
  pinMode(BUZZER, OUTPUT); 
  pinMode(bluePin, OUTPUT);
  pinMode(releR1, OUTPUT);
  pinMode(sensorPirP1, INPUT);
  pinMode(sensorEcoP1, INPUT);
  pinMode(sensorPirP2, INPUT);
  pinMode(sensorEcoP2, INPUT);
  digitalWrite(releR1, HIGH);
  pinMode(8, OUTPUT);
 
  mySerialPower();
  GSM_init();
  delay(15000);
  countdown();
  digitalWrite(bluePin, HIGH);
  delay(2000);
  digitalWrite(bluePin, LOW);
  delay(1000);
  Serial.println("Alarma lista para ser activada...");
}

void loop(){
  userSMSCheck();
  if(state == ON){
    if(monitoring == ON){
      lecturaPirP1 = analogRead(sensorPirP1);
      lecturaEcoP1 = analogRead(sensorEcoP1);
      if((lecturaPirP1 > 450) and (lecturaEcoP1 > 450)){
        Serial.println("ALARMA ZONA Uno!!...");
        activate_ALERT("1");
      }
      lecturaPirP2 = digitalRead(sensorPirP2);
      lecturaEcoP2 = digitalRead(sensorEcoP2);
      if((lecturaPirP2 == HIGH) and (lecturaEcoP2 == HIGH)){
        Serial.println("ALARMA ZONA Dos!!...");
        activate_ALERT("2");
      }
    }
    else{
        alertTimeOnCheck();
        Serial.println("Alarma auto-reactivada.");
    }
  }
}

void mySerialPower(){
  digitalWrite(8, LOW);
  delay(1000);
  digitalWrite(8, HIGH);
  delay(2000);
  digitalWrite(8, LOW);
  delay(3000);
}

void GSM_init(){
  Serial.begin(SERIAL_BAUDRATE);
  SIM900->begin(GSM_BAUDRATE);
  SIM900->println("AT");
  updateSerial();
  SIM900->println("AT+CREG=1");
  updateSerial();
  delay(10000);
  SIM900->println("AT+CMGF=1");
  updateSerial();
  delay(100);
  SIM900->println("AT+CNMI=1,2,0,0,0");
  updateSerial();
  SIM900->println("AT+CSQ");
  updateSerial();
  SIM900->println("AT+CREG?");
  updateSerial();
}

void countdown(){
  for(int i=3;i>1;i--){
    if(i>10){
      beep(50,50,1);
      delay(100);
    }else{
      beep(50,50,2);
    }
    delay(900);
  }
  beep(50, 50, 10);
}

void beep(int msON, int msOFF, int rep) {
  for (int i = 0; i < rep; i++) {
    digitalWrite(BUZZER, HIGH);
    delay(msON);//wait for X ms
    digitalWrite(BUZZER, LOW);
    delay(msOFF);
  }
}

void userSMSCheck(){
  incomingSMS = "";
  if(SIM900->available()){
    incomingSMS = SIM900->readString();
  }
  if((incomingSMS.indexOf("+xxxxxxxxxxxxxxx")>=0) or (incomingSMS.indexOf("+zzzzzzzzzzzzzz")>=0)){
    if(incomingSMS.indexOf("Reset")>=0){
      Serial.println("Procesando Reseteo...");
      RESET();
      Serial.println("Alarma reactivada...");
    } 
    if(incomingSMS.indexOf("Off")>=0){
      Serial.println("Procesando desactivación...");
      switch_OFF();
      Serial.println("Desactivada");
      msessage = "ALARMA DESACTIVADA.";
      sendSMS(msessage);
    } 
    if(incomingSMS.indexOf("On")>=0){
      Serial.println("Procesando activación...");
      switch_ON();
      Serial.println("Activada");
    }
  }
}

void sendSMS(String mensajeSale){
  SIM900->println("AT");
  updateSerial();
  delay(500);
  SIM900->println("AT+CMGS=\"+xxxxxxxxxxxxx\"");
  updateSerial();
  SIM900->print(mensajeSale);
  SIM900->write(26);
  updateSerial();
}

void updateSerial(){
  delay(500);
  while (Serial.available())
  {
    SIM900->write(Serial.read());
  }
  if (SIM900->available()){
    while(SIM900->available())
    {
      Serial.write(SIM900->read());
    }
  }
}

void activate_ALERT(String zona){
  monitoring = OFF;
  msessage = "SE HA ACTIVADO LA ALARMA EN ZONA " + zona + ". AutoReseteo en 25seg.";
  sendSMS(msessage);
  //digitalWrite(releR1, LOW);
  delay(25000);
  //digitalWrite(releR1, HIGH);
}

void switch_ON(){
  digitalWrite(releR1, LOW);
  delay(100);
  digitalWrite(releR1, HIGH);
  delay(25000);
  state = ON;
  monitoring = ON;
}

void switch_OFF(){
  state = OFF;
  monitoring = OFF;
  delay(200);
  digitalWrite(releR1, LOW);
  delay(100);
  digitalWrite(releR1, HIGH);
  delay(500);
  digitalWrite(releR1, LOW);
  delay(100);
  digitalWrite(releR1, HIGH);
  delay(200);
}

void RESET(){
  switch_OFF();
  delay(2000);
  switch_ON();
}

void alertTimeOnCheck(){
  RESET();
}

surbyte

Se como funciona un delay, es una interrupción de x tiempo a la ejecución del programa. Millis no me ah funcionado como quiero por eso no lo use. El tema es que arduino es cíclico y de un solo hilo o tarea (si fuera multatera y con ejecuciones paralelas podría crear interrupciones y hacer lo que quiera).

gatul

Justamente, me queda eso por resolver y el tema del status de la SIM (controla status y si está offline ponerla online de nuevo). El problema de que se alarma la zona2 al recibir mensaje esta resuelto.

Gracias!!

Yo creo que el modo de programación que estas usando puedo generarte problemas en algún momento del que te va a costar salir.
O sea que simplemente estas programando mal y es lógico que asi sea cuando estas haciendo tus primeros programas.
A mi me llevó un buen tiempo leyendo foros en inglés cuando vi en muchos comentarios que les decían..

tu problema es el delay()
tu problema es el delay()
tu problema es el delay()
.
.
tu problema es el delay()

imagina que esos fueron 100 hilos diferentes.

Entonces cómo se resuelve... ahhh => no uso UN SOLO DELAY y en su lugar millis()
Pero... millis() no funciona como delay(). Claro que no!! no puedes reemplazar uno por otro tal como estaba tu código anterior. Ni por asomo, son intercambiables.

Es y resulta muy dificil cambiar del modo delay() al modo millis(). Creo que mas dificil es hacerlo en la cabeza que en otro sitio.

Por eso te sugerí que lo practiques por fuera de este sketch.
Casi todo lo que veo en tu programa tiene delay() de 100mseg como mínimo a 1 y 2 seg o mas (encontré uno de 25 seg).

Como pretendes aplicar millis() y que funcione como quieres? Es imposible.
Para usar millis() no debe haber ninguna interrupción o programa bloqueante, por eso se habla de códigos non-blocking que no interrumpen el flujo del programa.

Por eso te sugerí que vieras ejemplos donde cuando le envías una petición al SIM900 este responde via comandos y tu te quedas a la espera de dicha respuesta pero mientras puedes hacer otras cosas dando la sensación de tener la bendita multitarea.
Si solo se trata de programar de otro modo.

Sigue tal como estas, intenta no usar delay() que bloqueen demasiado el código, ve liberando su uso. Ejemplo
si necesitas un delay(2000) divídelo en delay(100) y ve contando 20 veces y durante éstos, puedes prestar atención a otra cosa.

Me gustaría mostrarte como hacerlo pero una buena inspección de tu código me hace ver que esta lleno de dela() que bloquean todos los caminos.

El loop general parece estar bien pero cuando se activa una zona me encuentro con

void activate_ALERT(String zona){
 //
  delay(25000);
 //
}

25 seguntos detenidos. Acá compruebas porque falla millis().
Ademas esta el llamado a SensSMS que incluye mas delay(), 500 solo a llegar a sendSMS y otros 500 al updateSerial o sea 1 segundo mas.
Todo eso hay que desarmarlo para que se libere los tiempos muertos.

Se debe trabajar en cada rutina para que funcione sin bloquearse o sea devolviendo el control hasta que un determinado evento se cumpla y quede resuelto lo que se le pidió.

Es como si fueras un profesor y le dices a 5 alumnos hagan una tarea pero no te quedas con el primero hasta que la termine sino que les dices.. cuando alguno termine levante la mano (bandera o flag) y me avisa.. entonces hago lo que debo hacer.

Bien, tanto comentario y no extraes nada positivo o tal vez si.

Cuando quieras hacer la versión 2.0 hablamos.

Hola!!

surbyte

Coincido con que hay muchos delay, y estos son bloqueos a la continuidad de la ejecución, o sea son tiempo muerto del programa. Millis en su lugar noté que por el return vuelve a la linea anterior inmediata y se mantiene así en una ejecución constante sin tiempo muerto hasta que supera el limite de contador utilizado (ejemplo de uso pasado por bosoft más arriba), eso me permitiria mirar mensajes entrantes e interrumpir la alarma pero por alguna razón me pone en HIGH los pines de un sensor al usar millis. Me armaré otro código con otro arduino y sensores como banco de pruebas.

Sigue tal como estas, intenta no usar delay() que bloqueen demasiado el código, ve liberando su uso. Ejemplo
si necesitas un delay(2000) divídelo en delay(100) y ve contando 20 veces y durante éstos, puedes prestar atención a otra cosa.

Eso lo podría usar, mientras genero version 2.0 usando millis, para interrumpir la alarma en caso de mandar un sms de Off durante la misma.

Haré pruebas e iré compartiendo avances.

Gracias!.

Creo que tu plan de acción es no VARIAR demasiado porque como dije (seré reinterativo) es un cambio de cabeza de programador el que debes hacer y ahora tu cabeza solo piensa secuencialmente, asi que un modo menos secuencial es hacerlo con delays cortos y que mientras vayas viendo que puedes hacer con ese tiempo.... te das cuenta.
Si no te sirve.. olvídalo y deja todo para la 2.0
Ya veras que tu mismo diras luego que tienes una paella en la cabeza, al menos asi me pasó a mi al comienzo.

El solo hecho de programar en Arduino es una forma muy distinta de pensar. Se deben hacer un cambio de paradigma bastante amplio.

Así funciona casi como quiero, pero antes de seguir voy a aplicar el maquillaje y quitaré todos los delay, prints innecesarios, variables locas, etc... una vez que quede funcionando de igual manera veré de agregar control de status de la SIM por si se sale de linea:

#include <SoftwareSerial.h>
#include <Arduino.h>

/*** PARÁMETROS ***/
/******************************/
#define BUZZER 5
#define releR1 2
#define bluePin 4
#define SERIAL_BAUDRATE 9600
#define GSM_BAUDRATE 9600
#define RX_pin 10
#define TX_pin 11
#define ON 1
#define OFF 0
#define sensorPirP1 A0
#define sensorEcoP1 A1
#define sensorPirP2 6
#define sensorEcoP2 7
/******************************/

bool state, monitoring;
int lecturaPirP1, lecturaEcoP1, lecturaPirP2, lecturaEcoP2;
int x = 0;
SoftwareSerial *SIM900;
String incomingSMS, msessage;
 
void setup(){
  state = OFF;
  monitoring = OFF;
  SIM900 = new SoftwareSerial(RX_pin, TX_pin);
  pinMode(BUZZER, OUTPUT); 
  pinMode(bluePin, OUTPUT);
  pinMode(releR1, OUTPUT);
  pinMode(sensorPirP1, INPUT);
  pinMode(sensorEcoP1, INPUT);
  pinMode(sensorPirP2, INPUT);
  pinMode(sensorEcoP2, INPUT);
  digitalWrite(releR1, HIGH);
  pinMode(8, OUTPUT);
 
  mySerialPower();
  GSM_init();
  delay(15000);
  countdown();
  digitalWrite(bluePin, HIGH);
  delay(2000);
  digitalWrite(bluePin, LOW);
  delay(1000);
  Serial.println("Alarma lista para ser activada...");
}

void loop(){
  userSMSCheck();
  if(state == ON){
    if(monitoring == ON){
      lecturaPirP1 = analogRead(sensorPirP1);
      lecturaEcoP1 = analogRead(sensorEcoP1);
      if((lecturaPirP1 > 450) and (lecturaEcoP1 > 450)){
        Serial.println("ALARMA ZONA Uno!!...");
        activate_ALERT("1");
      }
      lecturaPirP2 = digitalRead(sensorPirP2);
      lecturaEcoP2 = digitalRead(sensorEcoP2);
      if((lecturaPirP2 == HIGH) and (lecturaEcoP2 == HIGH)){
        Serial.println("ALARMA ZONA Dos!!...");
        activate_ALERT("2");
      }
    }
    else{
        alertTimeOnCheck();
        Serial.println("Alarma auto-reactivada.");
    }
  }
}

void mySerialPower(){
  digitalWrite(8, LOW);
  delay(1000);
  digitalWrite(8, HIGH);
  delay(2000);
  digitalWrite(8, LOW);
  delay(3000);
}

void GSM_init(){
  Serial.begin(SERIAL_BAUDRATE);
  SIM900->begin(GSM_BAUDRATE);
  SIM900->println("AT");
  updateSerial();
  SIM900->println("AT+CREG=1");
  updateSerial();
  delay(10000);
  SIM900->println("AT+CMGF=1");
  updateSerial();
  delay(100);
  SIM900->println("AT+CNMI=1,2,0,0,0");
  updateSerial();
  SIM900->println("AT+CSQ");
  updateSerial();
  SIM900->println("AT+CREG?");
  updateSerial();
}

void countdown(){
  for(int i=3;i>1;i--){
    if(i>10){
      beep(50,50,1);
      delay(100);
    }else{
      beep(50,50,2);
    }
    delay(900);
  }
  beep(50, 50, 10);
}

void beep(int msON, int msOFF, int rep) {
  for (int i = 0; i < rep; i++) {
    digitalWrite(BUZZER, HIGH);
    delay(msON);//wait for X ms
    digitalWrite(BUZZER, LOW);
    delay(msOFF);
  }
}

void userSMSCheck(){
  incomingSMS = "";
  if(SIM900->available()){
    incomingSMS = SIM900->readString();
  }
  if((incomingSMS.indexOf("+xxxxxxxxxxxxxx")>=0) or (incomingSMS.indexOf("+zzzzzzzzzzzzzzz")>=0)){
    if(incomingSMS.indexOf("Reset")>=0){
      Serial.println("Procesando Reseteo...");
      RESET();
      Serial.println("Alarma reactivada...");
    } 
    if(incomingSMS.indexOf("Off")>=0){
      Serial.println("Procesando desactivación...");
      switch_OFF();
      Serial.println("Desactivada");
      msessage = "ALARMA DESACTIVADA.";
      sendSMS(msessage);
    } 
    if(incomingSMS.indexOf("On")>=0){
      Serial.println("Procesando activación...");
      switch_ON();
      Serial.println("Activada");
    }
  }
}

void sendSMS(String mensajeSale){
  SIM900->println("AT");
  updateSerial();
  delay(500);
  SIM900->println("AT+CMGS=\"+xxxxxxxxxxxxxx\"");
  updateSerial();
  SIM900->print(mensajeSale);
  SIM900->write(26);
  updateSerial();
}

void updateSerial(){
  delay(500);
  while (Serial.available())
  {
    SIM900->write(Serial.read());
  }
  if (SIM900->available()){
    while(SIM900->available())
    {
      Serial.write(SIM900->read());
    }
  }
}

void activate_ALERT(String zona){
  monitoring = OFF;
  msessage = "SE HA ACTIVADO LA ALARMA EN ZONA " + zona + ". AutoReseteo en 25seg.";
  sendSMS(msessage);
  digitalWrite(releR1, LOW);
  x = 0;
  do
  {
    delay(200);
    userSMSCheck();
    if(state == OFF) break;
    x = x + 1;
  }while (x < 99);
  digitalWrite(releR1, HIGH);
}

void switch_ON(){
  digitalWrite(releR1, LOW);
  delay(100);
  digitalWrite(releR1, HIGH);
  x = 0;
  do
  {
    delay(100);
    x = x + 1;
  }while (x < 249);
  state = ON;
  monitoring = ON;
}

void switch_OFF(){
  state = OFF;
  monitoring = OFF;
  digitalWrite(releR1, HIGH);
  delay(500);
  digitalWrite(releR1, LOW);
  delay(100);
  digitalWrite(releR1, HIGH);
  delay(500);
  digitalWrite(releR1, LOW);
  delay(100);
  digitalWrite(releR1, HIGH);
  delay(200);
}

void RESET(){
  switch_OFF();
  delay(2000);
  switch_ON();
}

void alertTimeOnCheck(){
  RESET();
}

Veo que ha mejorado mucho.
Como has visto se puede quitar tanta interrupción al código y que sea mas fluido.
Buen trabajo.

Este es un ejemplo notable de lo que te pedí.. y sinceramente te felicito

do
  {
    delay(200);
    userSMSCheck();
    if(state == OFF) break;
    x = x + 1;
  }while (x < 99);

Aca a pesar de seguir usando delay() lo reduces a 200 mseg que es digamos aceptable y mientras chequeas el estado state por si se recibe un SMS.

Excelente!!

Por lo visto tu cabeza comienza a cambiar de metodología entiendase paradigma como tu mismo has dicho.

Varios trucos:

  • Constantes en mayúsculas para identificarlas fácilmente.
  • Define esto:
#define PAUSITA 200
#define PAUSOTA 1000

Ahora puede poner tus delays, mientras pruebas en algo como así:

delay(PAUSOTA)
delay(PAUSOTA*10)

Así para cambiar pausas no vas línea por línea, y no abuses del delay salvo que sea imprescindible que no hagas nada en ese tiempo.
Otra cosa, aunque @victorjam me va a odiar por esto:
Si pones delay mientras estás aprendiendo a manejar el código y el C++ te simplificas comprender qué estás haciendo y qué sucede porque el microcontrolador no nace nada, no está mal, es una buena manera de no complicarte la vida mientras le pillas el hilo (como decimos en españa) o mientras ves cómo es la vara (esa de Costa Rica que es donde vivo ahora)
Divide y vencerás, controla un elemento y, si es necesario, hazte una función que haga sólo eso, especializada (o un objeto, aunque eso es más avanzado).