Problemas para ativar e desativar o sensor PIR pela web

Olá senhores do fórum. Sou novo por aqui, mas preciso muito da ajuda de vocês.

Estou desenvolvendo minha própria automação residencial. Estou usando como base, o código abaixo (há algumas funções a mais para necessidade da aplicação), e um arduino ethernet shield.

O problema que estou enfrentando é no meu sistema de alarme, com sensor PIR. Tem um comando (?lAlarme) que define o status do alarme como verdadeiro e inicia a função "ligarAlarme()" que vocês podem conferir no código. E o problema é que, ao enviar esse comando ?lAlarme, o sensor não muda de estado, ou seja, se antes de eu ativar o alarme o valor dele era 0, depois que ativar, mesmo movimentando-se na frente dele, ele continua a entender como 0, e o programa nunca vai ler uma mudança. Porém, se eu enviar o comando quando o sensor estiver em 1, ou seja, com movimento frente a ele, o alarme é disparado, mas se eu desativar o alarme e ligar de novo, quando o sensor estiver em 0, continuará entendendo como 0.

Atenção, pelo serial monitor, o sensor muda de 0 para 1 normalmente, mas na função, ele só lê o valor do sensor no momento em que foi enviado o comando.

Confira o código:

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

byte mac[] = { 0x01,0x23,0x45,0x67,0x89,0xAB }; // Endereço Mac
byte ip[] = { 192, 168, 0, 50 }; // Endereço de Ip da sua Rede
EthernetServer server(80); // Porta de serviço

String readString = String(30); // string para buscar dados de endereço
boolean statusFiltro = false; // Variável para o status do led
boolean statusAlarme = false; // Status do meu alarme

/*
##########################
------Boolean Luzes-------
##########################
*/
boolean SL1C = false;
/*
##########################
------Boolean Luzes-------
##########################
*/
float temperatura = 0;
float ldr = 0;

int pin2 = 13;


//Definição dos componentes do alarme
int pinBuzzer = 7; 
int pinSensorPIR = 8;
int pinLed = 9;
int valorSensorPIR = 0;

void setup(){
  // Inicia o Ethernet
  Ethernet.begin(mac, ip);
  // Define o pino como saída
  // Inicia a comunicação Serial
  Serial.begin(9600); 
  
  pinMode(pinBuzzer, OUTPUT);
  pinMode(pinSensorPIR, INPUT);
  pinMode(pinLed, OUTPUT);
}

void loop(){
  // Criar uma conexão de cliente
  valorSensorPIR = digitalRead(pinSensorPIR); // Configuração do sensor
  Serial.print("Valor do Sensor PIR: ");  
  Serial.println(valorSensorPIR);
  delay(300);
  
  EthernetClient client = server.available();
  int valorLido = analogRead(0);
  temperatura = (valorLido/31);
  
  int valorLdr = analogRead(1);
  ldr = (valorLdr);
  
  if (client) {
    while (client.connected())
    {
      if (client.available())
      {
        char c = client.read();
        // ler caractere por caractere vindo do HTTP
        if (readString.length() < 30)
        {
          // armazena os caracteres para string
          readString += (c);
        }
        
        //se o pedido HTTP terminou
        if (c == '\n')
          {
         if(readString.indexOf("lAlarme")>=0){ // Se o comando lAlarme for recebido ele muda o status e faz a função ligarAlarme
            statusAlarme = true;
             
             ligarAlarme();
             
          }
          if(readString.indexOf("dAlarme")>=0){ // Se receber o comando dAlarme, apenas muda o status e desliga o alarme
            statusAlarme = false;
            desligarAlarme();
          }
          if(readString.indexOf("lFiltro")>=0){
            statusFiltro = true;
          }
          if(readString.indexOf("dFiltro")>=0){
            statusFiltro = false;
          }
          if(readString.indexOf("L1C")>=0){
            if(SL1C){
              digitalWrite(pin2, LOW);
              SL1C = false;
            }else{
              digitalWrite(pin2, HIGH);
              SL1C = true;
            }
          }
        // dados HTML de saída começando com cabeçalho padrão
        client.println("HTTP/1.1 200 OK");
        client.println("Content-Type: text/html");
        client.println();
        
        client.print("<font size='20'>");
       // separa as linhas
        
        if(statusAlarme){
        client.print("AlarmeOn");
        }else{
          client.print("AlarmeOff");
        }
       
        client.print("<P>");
        
        if(statusFiltro){
        client.print("FiltroOn");
        }else{
          client.print("FiltroOff");
        }
       
        client.print("<P>");
        
        client.print("Temperatura: ");
        client.print(temperatura);
        client.print(" graus Celsius");
        
        client.print("<P>");
        
        client.print("LDR: ");
        client.print(ldr);
        client.print(" lux");
        
        client.print("<P>");
        
        if(SL1C){
        client.print("LuzOn");
        }else{
          client.print("LuzOff");
        }
       
        
        //limpa string para a próxima leitura
        readString="";
        
        // parar cliente
        client.stop();
        }
      }
    }
  }
}

void ligarAlarme() { //Aqui ele executa a função de ligar o alarme, que na verdade, só lê o valor uma vez e depois sai da função (problema que citei lá em cima)

  if (valorSensorPIR == 1) { //Com o alarme ligado, só vai disparar se o sensor detectar movimento e se detectar, liga led e o buzzer, porém....
  digitalWrite(pinLed, HIGH);
  tone(pinBuzzer,1500);
}
} // Nesta função acima, ele deveria ficar executando várias vezes, para sempre verificar se o valor do sensor mudou, acho que o problema é que ao enviar o comando, ele passa pelo void "ligarAlarme" uma vez só, e por isso o problema ocorre. Mas não tenho certeza..

void desligarAlarme() { //Sem problemas nesse comando, onde ele apenas desliga tudo.
  //Desligando o led
  digitalWrite(pinLed, LOW);
  //Desligando o buzzer
  noTone(pinBuzzer);
}

Como citei nos comentários do próprio código, penso que o problema está em a função ligarAlarme ser lida uma única vez, por isso o alarme não é ativado.. Mas não sei como por isso em loop, para ter certeza de que a função seja lida constantemente..

Bom, acho que é isso. Por favor, quem souber o que pode ser feito me ajude, e se algo ficou confuso, diga e tentarei ser mais claro.
Desde já agradeço.

Não existe nenhum comando "?lAlarme". O que existe são os comandos "lAlarme" para ligar e "dAlarme" para desligar.
Uma coisa que também pode ser feita é adicionar algumas linhas de depuração, enviando para o serial monitor o estado dos acontecimentos. Qualquer coisa como:

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

byte mac[] = { 0x01,0x23,0x45,0x67,0x89,0xAB }; // Endereço Mac
byte ip[] = { 192, 168, 0, 50 }; // Endereço de Ip da sua Rede
EthernetServer server(80); // Porta de serviço

String readString = String(30); // string para buscar dados de endereço
boolean statusFiltro = false; // Variável para o status do led
boolean statusAlarme = false; // Status do meu alarme

/*
##########################
------Boolean Luzes-------
##########################
*/
boolean SL1C = false;
/*
##########################
------Boolean Luzes-------
##########################
*/
float temperatura = 0;
float ldr = 0;

int pin2 = 13;


//Definição dos componentes do alarme
int pinBuzzer = 7; 
int pinSensorPIR = 8;
int pinLed = 9;
int valorSensorPIR = 0;

void setup(){
  // Inicia o Ethernet
  Ethernet.begin(mac, ip);
  // Define o pino como saída
  // Inicia a comunicação Serial
  Serial.begin(9600); 
  
  pinMode(pinBuzzer, OUTPUT);
  pinMode(pinSensorPIR, INPUT);
  pinMode(pinLed, OUTPUT);
}

void loop(){
  // Criar uma conexão de cliente
  valorSensorPIR = digitalRead(pinSensorPIR); // Configuração do sensor
  Serial.print("Valor do Sensor PIR: ");  
  Serial.println(valorSensorPIR);
  delay(300);
  
  EthernetClient client = server.available();
  int valorLido = analogRead(0);
  temperatura = (valorLido/31);
  
  int valorLdr = analogRead(1);
  ldr = (valorLdr);
  
  if (client) {
    while (client.connected())
    {
      if (client.available())
      {
        char c = client.read();
        // ler caractere por caractere vindo do HTTP
        if (readString.length() < 30)
        {
          // armazena os caracteres para string
          readString += (c);
        }
        
        //se o pedido HTTP terminou
        if (c == '\n')
          {
             Serial.print("Mensagem recebida: ");
             Serial.println(readString);
         if(readString.indexOf("lAlarme")>=0){ // Se o comando lAlarme for recebido ele muda o status e faz a função ligarAlarme
             Serial.println("Alarme ACTIVADO.");
            statusAlarme = true;
             
             ligarAlarme();
             
          }
          if(readString.indexOf("dAlarme")>=0){ // Se receber o comando dAlarme, apenas muda o status e desliga o alarme
             Serial.println("Alarme DESACTIVADO.");
            statusAlarme = false;
            desligarAlarme();
          }
          if(readString.indexOf("lFiltro")>=0){
            statusFiltro = true;
          }
          if(readString.indexOf("dFiltro")>=0){
            statusFiltro = false;
          }
          if(readString.indexOf("L1C")>=0){
            if(SL1C){
              digitalWrite(pin2, LOW);
              SL1C = false;
            }else{
              digitalWrite(pin2, HIGH);
              SL1C = true;
            }
          }
        // dados HTML de saída começando com cabeçalho padrão
        client.println("HTTP/1.1 200 OK");
        client.println("Content-Type: text/html");
        client.println();
        
        client.print("<font size='20'>");
       // separa as linhas
        
        if(statusAlarme){
        client.print("AlarmeOn");
        }else{
          client.print("AlarmeOff");
        }
       
        client.print("<P>");
        
        if(statusFiltro){
        client.print("FiltroOn");
        }else{
          client.print("FiltroOff");
        }
       
        client.print("<P>");
        
        client.print("Temperatura: ");
        client.print(temperatura);
        client.print(" graus Celsius");
        
        client.print("<P>");
        
        client.print("LDR: ");
        client.print(ldr);
        client.print(" lux");
        
        client.print("<P>");
        
        if(SL1C){
        client.print("LuzOn");
        }else{
          client.print("LuzOff");
        }
       
        
        //limpa string para a próxima leitura
        readString="";
        
        // parar cliente
        client.stop();
        }
      }
    }
  }
}

void ligarAlarme() { //Aqui ele executa a função de ligar o alarme, que na verdade, só lê o valor uma vez e depois sai da função (problema que citei lá em cima)

  if (valorSensorPIR == 1) { //Com o alarme ligado, só vai disparar se o sensor detectar movimento e se detectar, liga led e o buzzer, porém....
  digitalWrite(pinLed, HIGH);
  tone(pinBuzzer,1500);
}
} // Nesta função acima, ele deveria ficar executando várias vezes, para sempre verificar se o valor do sensor mudou, acho que o problema é que ao enviar o comando, ele passa pelo void "ligarAlarme" uma vez só, e por isso o problema ocorre. Mas não tenho certeza..

void desligarAlarme() { //Sem problemas nesse comando, onde ele apenas desliga tudo.
  //Desligando o led
  digitalWrite(pinLed, LOW);
  //Desligando o buzzer
  noTone(pinBuzzer);
}

Entendi o que fez. Mas ainda não resolve o problema, simplesmente informa se houve ou não o comando. Quando disse que o comando era "?lAlarme" me referia o get que devia enviar na web, mas no arduino sim, o comando não tem esse ?, é apenas na web

Ex: http://192.168.0.50/?lAlarme

Mas então, o que deverá ser feito para ele ler o sensor constantemente? Pois como disse, ele só lê no momento em que foi enviado o comando.
Obrigado pela colaboração.

forumcc.png

O sensor detecta... Até aqui tudo bem, mas só vai disparar um alarme se quando tu, ligares o alarme ele estiver actuado.
Foi isso que programaste....

O que tu queres é dentro da loop ter algo deste genero.

If (valorSensorPIR ==1 && statusalarme == 1) {
   LigaBuzina(); // andam cá gatunos.
}

Mais nada.
Quando activares o alarme pela web, ele fica armado e quando ler o pir no loop, activa a buzina se for caso disso.

Calma, deixa ver se eu entendi, esse ligarBuzina seria o ligarAlarme()? Porém na função ligarAlarme vai ficar apenas isso:

digitalWrite(pinLed, HIGH);
  tone(pinBuzzer,1500);

e no comando lAlarme vai ficar isso:

if(readString.indexOf("lAlarme")>=0){ // Se o comando lAlarme for recebido ele muda o status e faz a função ligarAlarme
             Serial.println("Alarme ACTIVADO.");
            statusAlarme = true;
             if (valorSensorPIR ==1 && statusAlarme == 1) {
             ligarAlarme();
             
          }

É isso que disse?

Quando vi o programa, o que pensei foi que o problema estivesse na descodificação do comando. Já agora, não é muito boa política usar o objecto String.
Agora olhando um pouco melhor (e depois do comentário do bubulindo), vejo que o problema é outro. Na realidade são dois problemas. O primeiro é o if dentro da função ligarAlarme. Se esta função tem if porque é que a desligarAlarme não tem também? O segundo, como o bubulindo referiu, é que esta verificação apenas é feita quando é recebida a mensagem (o que não faz o mais pequeno sentido). Sendo assim, o programa deveria ser uma coisa do género:

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

byte mac[] = { 0x01,0x23,0x45,0x67,0x89,0xAB }; // Endereço Mac
byte ip[] = { 192, 168, 0, 50 }; // Endereço de Ip da sua Rede
EthernetServer server(80); // Porta de serviço

String readString = String(30); // string para buscar dados de endereço
boolean statusFiltro = false; // Variável para o status do led
boolean statusAlarme = false; // Status do meu alarme

/*
##########################
------Boolean Luzes-------
##########################
*/
boolean SL1C = false;
/*
##########################
------Boolean Luzes-------
##########################
*/
float temperatura = 0;
float ldr = 0;

int pin2 = 13;


//Definição dos componentes do alarme
int pinBuzzer = 7; 
int pinSensorPIR = 8;
int pinLed = 9;
int valorSensorPIR = 0;

void setup(){
  // Inicia o Ethernet
  Ethernet.begin(mac, ip);
  // Define o pino como saída
  // Inicia a comunicação Serial
  Serial.begin(9600); 
  
  pinMode(pinBuzzer, OUTPUT);
  pinMode(pinSensorPIR, INPUT);
  pinMode(pinLed, OUTPUT);
}

void loop(){
  // Criar uma conexão de cliente
  valorSensorPIR = digitalRead(pinSensorPIR); // Configuração do sensor
  Serial.print("Valor do Sensor PIR: ");  
  Serial.println(valorSensorPIR);
  delay(300);
  
  EthernetClient client = server.available();
  int valorLido = analogRead(0);
  temperatura = (valorLido/31);
  
  int valorLdr = analogRead(1);
  ldr = (valorLdr);
  
  if (valorSensorPIR == 1 && statusAlarme == true) { //Com o alarme ligado, só vai disparar se o sensor detectar movimento e se detectar, liga led e o buzzer, porém....
     ligarAlarme();
  }
  else {
     desligarAlarme();
  }

  if (client) {
    while (client.connected())
    {
      if (client.available())
      {
        char c = client.read();
        // ler caractere por caractere vindo do HTTP
        if (readString.length() < 30)
        {
          // armazena os caracteres para string
          readString += (c);
        }
        
        //se o pedido HTTP terminou
        if (c == '\n')
          {
             Serial.print("Mensagem recebida: ");
             Serial.println(readString);
         if(readString.indexOf("lAlarme")>=0){ // Se o comando lAlarme for recebido ele muda o status e faz a função ligarAlarme
             Serial.println("Alarme ACTIVADO.");
            statusAlarme = true;
          }
          if(readString.indexOf("dAlarme")>=0){ // Se receber o comando dAlarme, apenas muda o status e desliga o alarme
             Serial.println("Alarme DESACTIVADO.");
            statusAlarme = false;
          }
          if(readString.indexOf("lFiltro")>=0){
            statusFiltro = true;
          }
          if(readString.indexOf("dFiltro")>=0){
            statusFiltro = false;
          }
          if(readString.indexOf("L1C")>=0){
            if(SL1C){
              digitalWrite(pin2, LOW);
              SL1C = false;
            }else{
              digitalWrite(pin2, HIGH);
              SL1C = true;
            }
          }
        // dados HTML de saída começando com cabeçalho padrão
        client.println("HTTP/1.1 200 OK");
        client.println("Content-Type: text/html");
        client.println();
        
        client.print("<font size='20'>");
       // separa as linhas
        
        if(statusAlarme){
        client.print("AlarmeOn");
        }else{
          client.print("AlarmeOff");
        }
       
        client.print("<P>");
        
        if(statusFiltro){
        client.print("FiltroOn");
        }else{
          client.print("FiltroOff");
        }
       
        client.print("<P>");
        
        client.print("Temperatura: ");
        client.print(temperatura);
        client.print(" graus Celsius");
        
        client.print("<P>");
        
        client.print("LDR: ");
        client.print(ldr);
        client.print(" lux");
        
        client.print("<P>");
        
        if(SL1C){
        client.print("LuzOn");
        }else{
          client.print("LuzOff");
        }
       
        
        //limpa string para a próxima leitura
        readString="";
        
        // parar cliente
        client.stop();
        }
      }
    }
  }
}

void ligarAlarme() { //Aqui ele executa a função de ligar o alarme, que na verdade, só lê o valor uma vez e depois sai da função (problema que citei lá em cima)

  digitalWrite(pinLed, HIGH);
  tone(pinBuzzer,1500);
} // Nesta função acima, ele deveria ficar executando várias vezes, para sempre verificar se o valor do sensor mudou, acho que o problema é que ao enviar o comando, ele passa pelo void "ligarAlarme" uma vez só, e por isso o problema ocorre. Mas não tenho certeza..

void desligarAlarme() { //Sem problemas nesse comando, onde ele apenas desliga tudo.
  //Desligando o led
  digitalWrite(pinLed, LOW);
  //Desligando o buzzer
  noTone(pinBuzzer);
}

Que basicamente é o que o bubulindo estava a sugerir.

Ignore meu último post... Li de novo o que me mandou e entendi desta vez.

A função lAlarme seria na verdade esta:

if(readString.indexOf("lAlarme")>=0){ // Se o comando lAlarme for recebido ele muda o status e faz a função ligarAlarme
             Serial.println("Alarme ACTIVADO.");
            statusAlarme = true;    
         }

Apenas altera o status do alarme

e a função que me passaste

  if (valorSensorPIR == 1 && statusAlarme == 1) {
             ligarAlarme();
  }

seria em qualquer lugar no loop. Agora sim deu tudo certo.

Muito obrigado pela ajuda. Conto com o apoio de vocês para novas dúvidas e aprendizado.
Obrigado!

luisilva:
Quando vi o programa, o que pensei foi que o problema estivesse na descodificação do comando. Já agora, não é muito boa política usar o objecto String.
Agora olhando um pouco melhor (e depois do comentário do bubulindo), vejo que o problema é outro. Na realidade são dois problemas. O primeiro é o if dentro da função ligarAlarme. Se esta função tem if porque é que a desligarAlarme não tem também? O segundo, como o bubulindo referiu, é que esta verificação apenas é feita quando é recebida a mensagem (o que não faz o mais pequeno sentido). Sendo assim, o programa deveria ser uma coisa do género:

#include <SPI.h>

#include <String.h>
#include <Ethernet.h>

byte mac[] = { 0x01,0x23,0x45,0x67,0x89,0xAB }; // Endereço Mac
byte ip[] = { 192, 168, 0, 50 }; // Endereço de Ip da sua Rede
EthernetServer server(80); // Porta de serviço

String readString = String(30); // string para buscar dados de endereço
boolean statusFiltro = false; // Variável para o status do led
boolean statusAlarme = false; // Status do meu alarme

/*
##########################
------Boolean Luzes-------
##########################
/
boolean SL1C = false;
/

##########################
------Boolean Luzes-------
##########################
*/
float temperatura = 0;
float ldr = 0;

int pin2 = 13;

//Definição dos componentes do alarme
int pinBuzzer = 7;
int pinSensorPIR = 8;
int pinLed = 9;
int valorSensorPIR = 0;

void setup(){
 // Inicia o Ethernet
 Ethernet.begin(mac, ip);
 // Define o pino como saída
 // Inicia a comunicação Serial
 Serial.begin(9600);
 
 pinMode(pinBuzzer, OUTPUT);
 pinMode(pinSensorPIR, INPUT);
 pinMode(pinLed, OUTPUT);
}

void loop(){
 // Criar uma conexão de cliente
 valorSensorPIR = digitalRead(pinSensorPIR); // Configuração do sensor
 Serial.print("Valor do Sensor PIR: ");  
 Serial.println(valorSensorPIR);
 delay(300);
 
 EthernetClient client = server.available();
 int valorLido = analogRead(0);
 temperatura = (valorLido/31);
 
 int valorLdr = analogRead(1);
 ldr = (valorLdr);
 
 if (valorSensorPIR == 1 && statusAlarme == true) { //Com o alarme ligado, só vai disparar se o sensor detectar movimento e se detectar, liga led e o buzzer, porém....
    ligarAlarme();
 }
 else {
    desligarAlarme();
 }
       //se o pedido HTTP terminou
       if (c == '\n')
         {
            Serial.print("Mensagem recebida: ");
            Serial.println(readString);
        if(readString.indexOf("lAlarme")>=0){ // Se o comando lAlarme for recebido ele muda o status e faz a função ligarAlarme
            Serial.println("Alarme ACTIVADO.");
           statusAlarme = true;
         }
         if(readString.indexOf("dAlarme")>=0){ // Se receber o comando dAlarme, apenas muda o status e desliga o alarme
            Serial.println("Alarme DESACTIVADO.");
           statusAlarme = false;
         }

void ligarAlarme() { //Aqui ele executa a função de ligar o alarme, que na verdade, só lê o valor uma vez e depois sai da função (problema que citei lá em cima)

digitalWrite(pinLed, HIGH);
 tone(pinBuzzer,1500);
} // Nesta função acima, ele deveria ficar executando várias vezes, para sempre verificar se o valor do sensor mudou, acho que o problema é que ao enviar o comando, ele passa pelo void "ligarAlarme" uma vez só, e por isso o problema ocorre. Mas não tenho certeza..

void desligarAlarme() { //Sem problemas nesse comando, onde ele apenas desliga tudo.
 //Desligando o led
 digitalWrite(pinLed, LOW);
 //Desligando o buzzer
 noTone(pinBuzzer);
}




Que basicamente é o que o bubulindo estava a sugerir.

luisilva,

vi agora o que postou, mas acho que no código, não é necessário o uso do

else {
     desligarAlarme();
  }

Pelo menos, testei apenas com isso

if (valorSensorPIR == 1 && statusAlarme == 1) {
             ligarAlarme();
  }

e deu certo. Pois não há necessidade do else já que a função ligarAlarme está somente dentro desta condição, sendo impossível despertar o buzzer sem ser por esta condição.

Mas também não iria prejudicar o funcionamento. Então agradeço a ajuda de vocês, e o tópico se encontra resolvido agora.