Hola. He estado buscando un código para que, a través de una shield Ethernet, me envíe un correo cuando un sensor PIR detecte un movimiento.
He encontrado varios, pero no consigo que ninguno funcione. Ya tengo un servidor, con un usuario y contraseña, por lo que necesitaría un código para subir a la placa Arduino UNO de esos que te pide desde dónde se envía (FROM), a dónde se envía (TO) y, si fuera posible, con la autentificación del servidor, es decir, que pueda poner el usuario y la contraseña.
Espero haberme explicado bien y gracias por vuestra ayuda.
Hola. Siento haber tardado en responder, pero he estado todo este tiempo haciendo pruebas para poder enviar un email. Por fin lo conseguí; el fallo estaba en la contraseña de autentificación. Al abrir la cuenta en SMTP2GO me asignaron una contraseña por defecto para enviar email vía SMTP. Yo la codificaba en base 64, pero que no había manera de recibir ningún correo. Al final cambié a una contraseña personalizada y por fin pude conseguirlo. Lo comento por si le sirve a alguien en un futuro.
Ahora viene el segundo problema. Yo quería no sólo enviar porque sí un mail a través de Arduino, sino que lo hiciese al suceder un evento; en mi caso, cuando un sensor de PIR detectara movimiento. Lo que me muestra el monitor serial es lo siguiente:
Sistema Listo
Movimiento detectado!!!
conectando espere…
connectado
end
Sistema Listo
Movimiento detectado!!!
conectando espere…
connectado
end
Sistema Listo
Lo hace 2 veces seguidas y luego vuelve a entrar en modo “a la espera de movimiento”, pero no llega a lanzar el correo. Adjunto el código a ver si me ayudáis a encontrar el fallo.
#include <SPI.h>
#include <Ethernet.h>
int led = 5; // Pin 13 encenderá un led al detectar un movimiento
int SensorPir = 6; // elegir el pin de entrada para el sensor PIR
int valor = 0; // variable para leer el estado del pin 6
void(* Resetea) (void) = 0;//Funcíon Reset por soft para el arduino (como si apretaramos el botón reset)
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };//Dirección MAC de nuestro módulo ethernet
char server[] = "mail.smtp2go.com"; //Cambiar por la url del servidor a usar
IPAddress ip(192, 168, 1, 35);// Tomará esta ip si el servidor DHCP falla
EthernetClient client;
void setup() {
pinMode(led, OUTPUT); // declarmos led como salida(pin 5)
pinMode(SensorPir, INPUT); // declaramos SensorPir como entrada(pin 6)
digitalWrite(led, LOW);//Led 5 apagado
Serial.begin(9600);//Velocidad del puerto serie
while (!Serial) {
;
}
Serial.println("Sistema Listo");//Nos indica que ya estamos en condiciones de enviar un correo
}
void loop() {
valor = digitalRead(SensorPir); // leemos el valor de entrada
if (valor == HIGH) { // comprobamos si la entrada es HIGH
digitalWrite(led, HIGH); // Enciende el led
Serial.println("Movimiento detectado!!!");
delay(2000);
Envio_mail();//Llama a la función Envio_mail
}
}
//////////////////////////////////
void Envio_mail() {
delay(300);
////////////DHCP Activado////////////////////////////////
if (Ethernet.begin(mac) == 0) {
Serial.println("No se pudo configurar Ethernet mediante DHCP");
Ethernet.begin(mac, ip);
}
////////////DHCP desactivado////////////////
//Ethernet.begin(mac, ip);
delay(100);
Serial.println("conectando espere...");
if (client.connect(server, 2525)) {
Serial.println("connectado :-)");//Si se establece la conexión
client.println("AUTH LOGIN"); //see "http://base64-encoder-online.waraxe.us/"
client.println("xxxxxxxxx"); //Aqui pongo el usuario codificado en base 64
client.println("xxxxxxxxxx"); //Aqui pongo la contraseña codificada en base 64
// Put your "from" email address here
client.println("MAIL FROM:<xxxx@hotmail.com>"); //Seems you can write what you want here...
for(int i=0; i<999; ++i){
if(client.read() > 0)
break;
}
client.println("RCPT TO:<yyyy@gmail.com>");
for(int i=0; i<999; ++i){
if(client.read() > 0)
break;
}
client.println("DATA");
for(int i=0; i<999; ++i){
if(client.read() > 0)
break;
}
//Sender
client.println("from: xxxx@hotmail.com"); //Sender address
client.println("to: yyyy@gmail.com"); //Receiver address
client.println("SUBJECT: From your arduino");
client.println("QUIT");
for (int i = 0; i<999; ++i){
if(i > 998){
Serial.println("error: No response");
}
if(client.read() > 0)
break;
}
client.println();
Serial.println("end");
}
else {
Serial.println("Failed");
client.println("QUIT"); //Disconnection
}
client.stop();
Resetea();
}
Gracias surbyte por tus felicitaciones y por tu labor en el foro.
Desafortunadamente, como indicaba anteriormente, no he podido terminar el proyecto, pues aunque he conseguido enviar un mail cargando un sketch específico para ello, aún no he logrado envíar el correo al detectar el movimiento. Mis conocimientos de programación son pocos, pero intuyo que simplemente puede ser alguna llave mal colocada (o que me falta poner alguna), pues es como si al conectar con la red saltara directamente al final, sin pasar por la parte de "envío de mail".
¿Alguna sugerencia o idea de lo que puede estar fallando? Gracias.
Buenas Rubikub, según el sketch que has puesto y el la salida que indicas, si te entra en la función de enviar_mail, por tanto como es lógico el fallo para que no te envie el correo debe estar en esa función. Comparala con el sketch de envio que te ha funcionado, debe haber alguna diferencia.
De todas formas no creo que ese código sea bueno para tu propósito, pienso que una forma mejor de hacerlo sea mediante una interrupción, me explico…conecta el sensor PIR a un pin con interrupción, por ejemplo el pin 2 que tiene atada la interrupción 0 en el arduino UNO (tendrás que leer un poco acerca de las interrupciónes). Cuando se produzca la interrupción incrementas un contador. Después en el loop vas comparando el valor del contador con su valor anterior que almacenas en otra variable y si este contador se ha incrementado (ha detectado movimiento), llamas a la función enviar_mail…y te olvidas de resetear el arduino, como haces ahora.
Además también deberías plantearte añadirle algún watchdog por si se cuelga.
Hola, Alfredomrh y surbyte. Por fin he conseguido mi propósito. He estado buscando por internet otros códigos que hicieran la función que necesitaba y, aunque no ha sido sencillo, al final he dado con uno en el que haciendo unas pequeñas modificaciones, ha funcionado. Lo adjunto por si alguien lo necesita. Por mi parte, y si el moderador lo considera oportuno, puede cerrar el tema y darlo por solucionado. Gracias a ambos.
#include <SPI.h>
#include <Ethernet.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // La mac que tenga tu tarjeta
char smtpServer[] = "mail.smtp2go.com"; // Servidor SMTP (yo utilizo la plataforma smtp2go)
EthernetClient client;
/////////////////////////////
//VARS
//the time we give the sensor to calibrate (10-60 secs according to the datasheet)
int calibrationTime = 30;
//the time when the sensor outputs a low impulse
long unsigned int lowIn;
//the amount of milliseconds the sensor has to be low
//before we assume all motion has stopped
long unsigned int pause = 5000;
boolean lockLow = true;
boolean takeLowTime;
int pirPin = 3; //the digital pin connected to the PIR sensor's output
int ledPin = 13;
int nPIR_detect;
void setup()
{
Ethernet.begin(mac);
Serial.begin(9600);
pinMode(pirPin, INPUT);
digitalWrite(pirPin, LOW);
//give the sensor some time to calibrate
Serial.print("Calibrando el sensor ");
for(int i = 0; i < calibrationTime; i++){
Serial.print(".");
delay(1000);
}
Serial.println(" hecho");
Serial.println("SENSOR ACTIVO");
delay(50);
nPIR_detect = 0;
}
void loop()
{
delay(1000);
if(PIR_detected()) // PIR : HIGH
{
if (client.available()) {
char c = client.read();
Serial.print(c);
}
Serial.println("Conectando...");
if (client.connect(smtpServer, 2525)) {
Serial.println("Conectado");
client.println("EHLO arduino");
client.println("AUTH LOGIN"); //ver "http://base64-encoder-online.waraxe.us/"
client.println("xxxxxxxxxxxxxxxxxxx"); //Aquí pongo el usuario codificado en base 64
client.println("xxxxxxxxxxxxxxxxxxx"); //Aquí pongo la contraseña codificada en base 64
client.println("MAIL FROM:<xxxx@hotmail.com>"); //La cuenta con la que se envía el correo
client.println("RCPT TO:<yyyy@gmail.com>"); // La cuenta a la que se envía el correo
client.println("DATA");
client.println("From: <xxxx@hotmail.com>"); //La cuenta con la que se envía el correo
client.println("TO: <yyyy@gmail.com>"); // La cuenta a la que se envía el correo
client.println("SUBJECT: Movimiento detectado!!!"); // Título del correo que se enviará
client.println();
client.println("Movimiento detectado."); // Texto que aparecerá en el correo
client.println("Alarma!!!."); // Texto que aparecerá en el correo
client.println(".");
client.println(".");
delay(1000);
client.stop();
Serial.println("Correo enviado");
delay(30000);
}
else
{
Serial.println("Fallo de conexión");
}
}
}
boolean PIR_detected()
{
boolean bPIR;
if(digitalRead(pirPin) == HIGH){
digitalWrite(ledPin, HIGH); //the led visualizes the sensors output pin state
if(lockLow){
//makes sure we wait for a transition to LOW before any further output is made:
lockLow = false;
Serial.println("---");
Serial.print("Movimiento detectado a los ");
Serial.print(millis()/1000);
Serial.println(" seg");
delay(50);
}
takeLowTime = true;
bPIR = true;
}
if(digitalRead(pirPin) == LOW){
digitalWrite(ledPin, LOW); //the led visualizes the sensors output pin state
if(takeLowTime){
lowIn = millis(); //save the time of the transition from high to LOW
takeLowTime = false; //make sure this is only done at the start of a LOW phase
}
//if the sensor is low for more than the given pause,
//we assume that no more motion is going to happen
if(!lockLow && millis() - lowIn > pause){
//makes sure this block of code is only executed again after
//a new motion sequence has been detected
lockLow = true;
Serial.print("Movimiento finalizado a los "); //output
Serial.print((millis() - pause)/1000);
Serial.println(" seg");
delay(50);
}
bPIR = false;
}
return bPIR;
}
En lo personal me alegro que lo resolvieran. También me alegra que sepas buscar lo que necesitas pero y acá mi comentario me da pena que no insistieras con el código que ya tenías para que hiciera lo que necesitabas.
de todas formas no creo que ese código sea bueno para tu propósito, pienso que una forma mejor de hacerlo sea mediante una interrupción,
No había leido esto!!
Claro que todos tenemos criterios diferentes para las cosas pero nada mas desatinado que usar una interrupción para algo tan trivial y lento como un PIR detectando algo.
El micro tiene todo el tiempo del mundo para detectar un cambio de estado que es todo lo que necesita para enviar un email.
Si lo envia o no depende de hacer bien las cosas en ese aspecto.
En este caso
void loop() {
valor = digitalRead(SensorPir); // leemos el valor de entrada
if (valor == HIGH) { // comprobamos si la entrada es HIGH
digitalWrite(led, HIGH); // Enciende el led
Serial.println("Movimiento detectado!!!");
delay(2000);
Envio_mail();//Llama a la función Envio_mail
}
}
El problema esta en delay(2000); y en la forma en que se detecta el movimiento.
Detectar valor == HIGH eso ocurre por mucho tiempo tanto como este ajustado el PIR para hacerlo y puede ser 10 o mas segundos.
Cuantas veces el loop se cumple en ese tiempo?
En el segundo caso veo
void loop()
{
delay(1000);
if(PIR_detected()) // PIR : HIGH
{
Arranca mal y luego tiene una función PIR_detected() hecha con millis() donde de nuevo hay un delay(50) menor pero delay al fin.
Entonces que sentido tiene el delay(1000)? Ninguno.
Lo que se debe hacer es ver el cambio de estado, que el PIR pase de NO detectado a Detectado, y no usar delay, y el micro tiene toda la vida para observar que eso ocurra y luego si enviar el email y tomar la precaución que no vuelva a hacerlo por X tiempo para no llenar el celular de SMS.
surbyte:
No había leido esto!!
Claro que todos tenemos criterios diferentes para las cosas pero nada mas desatinado que usar una interrupción para algo tan trivial y lento como un PIR detectando algo.
Entiendo que por la lentitud del sensor no interese manejarlo con una interrupción, la verdad es que no lo he probado. Mi idea era usar una interrupción para incrementar un contador y después enviar un mail cuando el contador alcance un valor.
El otro día en un comentario que me hace IgnoranteAbsoluto acerca de usar sprintf y un buffer que consume RAM le dije... algo asi como "y cual es el problema en usar RAM si esta ahi para usarla y si la necesitas entonces si estoy de acuerdo con preservar RAM"
Luego de mi comentario respecto de la interrupción me parece que se invierten las razones..
Puedes usar la interrupción? Si claro que puedes. Hay alguna restricción. No.
Hay un método mejor? No. Ambos son igualmente eficaces, el que yo propuse y usar Interrupciones.
Asi que todo queda a criterio de cada uno.
Si me preguntas, tu usarías interrupciones para un PIR? Mi respuesta es NO. Uso interrupciones cuando de acuerdo a mi criterio se require su uso. Una señal lenta o incluso una rápida sin ningun desespero por detectarla no tiene razón para mi en usar interrupciones.
Eso es todo.. quería escribirlo para que quede claro que son caminos a seguir.
Perfecto, agradezco tu explicación y entiendo que son diferencias de criterio, pero por lo que explicas tienes razón, tu enfoque es más adecuado en este caso.